From f2d67487831f315fea90280711bb882929ce01c5 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Sat, 19 Nov 2022 00:47:54 -0500 Subject: [PATCH 01/36] config integration into builder --- bom/pom.xml | 12 + common/config/pom.xml | 27 + .../helidon/common/config/ConfigHolder.java | 105 +++ .../common/config/spi/ConfigProvider.java | 38 + .../common/config/spi/package-info.java | 20 + common/config/src/main/java/module-info.java | 5 + .../spi/testsubjects/TestConfigProvider.java | 46 + .../common/config/test/ConfigHolderTest.java | 51 ++ ...o.helidon.common.config.spi.ConfigProvider | 17 + .../processor/ConfigMetadataHandler.java | 4 +- pico/builder-config/builder-config/README.md | 3 + .../etc/spotbugs/checkstyle-suppressions.xml | 26 + .../builder-config/etc/spotbugs/exclude.xml | 33 + pico/builder-config/builder-config/pom.xml | 100 +++ .../pico/builder/config/ConfigBean.java | 99 ++ .../pico/builder/config/package-info.java | 20 + .../spi/ConfigBeanBuilderValidator.java | 192 ++++ .../spi/ConfigBeanBuilderValidatorHolder.java | 68 ++ .../ConfigBeanBuilderValidatorProvider.java | 33 + .../builder/config/spi/ConfigBeanInfo.java | 81 ++ .../builder/config/spi/ConfigBeanMapper.java | 40 + .../config/spi/ConfigBeanMapperHolder.java | 66 ++ .../config/spi/ConfigBeanMapperProvider.java | 33 + .../builder/config/spi/ConfigResolver.java | 71 ++ .../config/spi/ConfigResolverHolder.java | 58 ++ .../config/spi/ConfigResolverMapRequest.java | 48 + .../config/spi/ConfigResolverProvider.java | 31 + .../config/spi/ConfigResolverRequest.java | 60 ++ .../config/spi/DefaultConfigResolver.java | 120 +++ .../config/spi/GeneratedConfigBean.java | 48 + .../config/spi/GeneratedConfigBeanBase.java | 71 ++ .../spi/GeneratedConfigBeanBuilder.java | 61 ++ .../spi/GeneratedConfigBeanBuilderBase.java | 73 ++ .../config/spi/GeneratedConfigCommon.java | 62 ++ .../builder/config/spi/ResolutionCtx.java | 187 ++++ .../builder/config/spi/StringValueParser.java | 39 + .../config/spi/StringValueParserHolder.java | 58 ++ .../config/spi/StringValueParserProvider.java | 33 + .../pico/builder/config/spi/package-info.java | 20 + .../src/main/java/module-info.java | 36 + .../spi/test/ConfigBeanMapperHolderTest.java | 35 + .../ConfigBuilderValidatorHolderTest.java | 35 + .../spi/test/ConfigResolverHolderTest.java | 35 + .../spi/test/MetaConfigBeanInfoTest.java | 55 ++ .../spi/test/StringValueParserHolderTest.java | 35 + pico/builder-config/pom.xml | 42 + pico/builder-config/processor/README.md | 3 + pico/builder-config/processor/pom.xml | 78 ++ .../tools/ConfigBeanBuilderCreator.java | 389 ++++++++ .../config/processor/tools/package-info.java | 20 + .../processor/src/main/java/module-info.java | 38 + .../tests/ConfigBeanBuilderCreatorTest.java | 37 + .../builder-config/tests/configbean/README.md | 2 + pico/builder-config/tests/configbean/pom.xml | 142 +++ .../builder/config/fakes/FakeClientAuth.java | 49 + .../fakes/FakeComponentTracingConfig.java | 232 +++++ .../builder/config/fakes/FakeKeyConfig.java | 842 +++++++++++++++++ .../config/fakes/FakeKeystoreConfig.java | 134 +++ .../config/fakes/FakeNettyClientAuth.java | 26 + .../config/fakes/FakePathTracingConfig.java | 179 ++++ .../config/fakes/FakeRoutingConfig.java | 694 ++++++++++++++ .../config/fakes/FakeServerConfig.java | 763 ++++++++++++++++ .../config/fakes/FakeServerLifecycle.java | 37 + .../config/fakes/FakeSocketConfig.java | 847 +++++++++++++++++ .../fakes/FakeSpanLogTracingConfig.java | 129 +++ .../config/fakes/FakeSpanTracingConfig.java | 258 ++++++ .../config/fakes/FakeTraceableConfig.java | 55 ++ .../pico/builder/config/fakes/FakeTracer.java | 103 +++ .../config/fakes/FakeTracingConfig.java | 245 +++++ .../builder/config/fakes/FakeWebServer.java | 56 ++ .../config/fakes/FakeWebServerTlsConfig.java | 437 +++++++++ .../config/fakes/SSLContextConfig.java | 204 +++++ .../pico/builder/config/fakes/WebServer.java | 773 ++++++++++++++++ .../config/fakes/config/FakeClientAuth.java | 49 + .../config/FakeComponentTracingConfig.java | 223 +++++ .../config/fakes/config/FakeKeyConfig.java | 839 +++++++++++++++++ .../fakes/config/FakeKeystoreConfig.java | 132 +++ .../fakes/config/FakeNettyClientAuth.java | 26 + .../fakes/config/FakePathTracingConfig.java | 179 ++++ .../fakes/config/FakeRoutingConfig.java | 699 ++++++++++++++ .../config/fakes/config/FakeServerConfig.java | 763 ++++++++++++++++ .../fakes/config/FakeServerLifecycle.java | 38 + .../config/fakes/config/FakeSocketConfig.java | 849 ++++++++++++++++++ .../config/FakeSpanLogTracingConfig.java | 128 +++ .../fakes/config/FakeSpanTracingConfig.java | 258 ++++++ .../fakes/config/FakeTraceableConfig.java | 56 ++ .../config/fakes/config/FakeTracer.java | 103 +++ .../fakes/config/FakeTracingConfig.java | 244 +++++ .../fakes/config/FakeWebServerTlsConfig.java | 438 +++++++++ .../config/fakes/config/SSLContextConfig.java | 201 +++++ .../config/testsubjects/ClientConfig.java | 36 + .../config/testsubjects/CommonConfig.java | 36 + .../config/testsubjects/ServerConfig.java | 33 + .../configbean/src/main/java/module-info.java | 31 + .../config/test/BasicConfigBeanTest.java | 71 ++ pico/builder-config/tests/pom.xml | 49 + pico/builder/pom.xml | 5 + .../builder/processor/tools/BodyContext.java | 26 +- .../tools/DefaultBuilderCreator.java | 317 ++++--- .../processor/tools/GenerateJavadoc.java | 8 +- .../processor/tools/GenerateMethod.java | 6 +- ...sitor.java => GenerateVisitorSupport.java} | 6 +- pico/builder/tests/builder/pom.xml | 7 +- .../test/testsubjects/ComplexCase.java | 7 + .../builder/src/main/java/module-info.java | 3 +- .../builder/api/test/ComplexCaseTest.java | 3 +- pico/builder/tests/pom.xml | 9 + pico/pom.xml | 1 + .../helidon/pico/types/DefaultTypeName.java | 38 +- .../pico/types/test/DefaultTypeNameTest.java | 8 + 110 files changed, 14973 insertions(+), 156 deletions(-) create mode 100644 common/config/src/main/java/io/helidon/common/config/ConfigHolder.java create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/package-info.java create mode 100644 common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java create mode 100644 common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java create mode 100644 common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider create mode 100644 pico/builder-config/builder-config/README.md create mode 100644 pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml create mode 100644 pico/builder-config/builder-config/etc/spotbugs/exclude.xml create mode 100644 pico/builder-config/builder-config/pom.xml create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java create mode 100644 pico/builder-config/builder-config/src/main/java/module-info.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java create mode 100644 pico/builder-config/pom.xml create mode 100644 pico/builder-config/processor/README.md create mode 100644 pico/builder-config/processor/pom.xml create mode 100644 pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java create mode 100644 pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java create mode 100644 pico/builder-config/processor/src/main/java/module-info.java create mode 100644 pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java create mode 100644 pico/builder-config/tests/configbean/README.md create mode 100644 pico/builder-config/tests/configbean/pom.xml create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/module-info.java create mode 100644 pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java create mode 100644 pico/builder-config/tests/pom.xml rename pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/{GenerateVisitor.java => GenerateVisitorSupport.java} (97%) diff --git a/bom/pom.xml b/bom/pom.xml index aa97afec567..0a95049ff32 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -1425,6 +1425,18 @@ ${helidon.version} + + + io.helidon.pico.builder.config + helidon-pico-builder-config + ${helidon.version} + + + io.helidon.pico.builder.config + helidon-pico-builder-config-processor + ${helidon.version} + + diff --git a/common/config/pom.xml b/common/config/pom.xml index 8657f6c8175..4ee63f3e723 100644 --- a/common/config/pom.xml +++ b/common/config/pom.xml @@ -33,6 +33,33 @@ 11 + + + io.helidon.common + helidon-common + + + jakarta.inject + jakarta.inject-api + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-core + test + + + diff --git a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java new file mode 100644 index 00000000000..d84dc6e3b59 --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java @@ -0,0 +1,105 @@ +/* + * 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.common.config; + +import java.util.Objects; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.concurrent.atomic.AtomicReference; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.config.spi.ConfigProvider; + +/** + * Provides access to the global {@link io.helidon.common.config.Config} singleton instance. + *

+ * Most callers are simply expected to call the {@link #config()} method to resolve the global configuration. Note, however, + * that the global configuration instance needs to be made available prior to calling the {@link #config()} method. There are + * two techniques for establishing the global configuration instance: (1) via the Java {@link java.util.ServiceLoader} and + * (2) programmatically via the {@link #config(io.helidon.common.config.Config)} method. The {@link #config()} method will + * apply the following strategy to resolve and cache the global config instance: + *

    + *
  1. if the instance is already been established and cached then use it.
  2. + *
  3. if the instance has programmatically been set then use it - this is the same as the cached instance.
  4. + *
  5. use the service loader to resolve the config instance, and if found then cache it.
  6. + *
+ * Note also that the {@link #reset()} method can be used to clear the cached instance. However, doing so should not be expected + * to alter any callers that have previously obtained the global configuration instance prior to calling the {@link #reset()} + * method. + *

+ * Note that this class is not thread safe. If the global configuration must be set programmatically then it should therefore + * be set on the main thread typically early in the jvm lifecycle. + * + * @see io.helidon.common.config.spi.ConfigProvider + */ +public class ConfigHolder { + private static final AtomicReference> INSTANCE = new AtomicReference<>(); + + private ConfigHolder() { + } + + /** + * Returns the global {@link io.helidon.common.config.Config} instance. + * + * @return the global instance + */ + public static Optional config() { + if (Objects.isNull(INSTANCE.get())) { + INSTANCE.set(load()); + } + return INSTANCE.get(); + } + + /** + * Proactively set the global configuration instance. Callers are reminded that {@link #reset()} must be called in order + * to clear any previously set global instance. Failure to do so will result in an exception being thrown. + * + * @param cfg the configuration + * @throws java.lang.IllegalStateException called if the config instance was previously been set + */ + public static void config(Config cfg) { + boolean set = INSTANCE.compareAndSet(null, + Optional.of(Objects.requireNonNull(cfg))); + if (!set) { + throw new IllegalStateException(Config.class.getSimpleName() + " already set"); + } + } + + /** + * Clears the config instance; not recommended for common use. + */ + public static void reset() { + System.Logger.Level level = Objects.nonNull(INSTANCE.get()) ? System.Logger.Level.INFO : System.Logger.Level.DEBUG; + System.Logger logger = System.getLogger(ConfigHolder.class.getName()); + logger.log(level, "resetting..."); + INSTANCE.set(null); + } + + private static Optional load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigProvider.class, ConfigProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return provider.get().__config(); + } + +} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java new file mode 100644 index 00000000000..df73647af6e --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java @@ -0,0 +1,38 @@ +/* + * 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.common.config.spi; + +import java.util.Optional; + +import io.helidon.common.config.Config; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link io.helidon.common.config.Config} instance. + * + * @see io.helidon.common.config.ConfigHolder + */ +public interface ConfigProvider { + + /** + * The service-loaded global {@link io.helidon.common.config.Config} instance. + * + * @return the global config instance + */ + // note that this needs to have double underscore since it is available in generated code + Optional __config(); + +} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/package-info.java b/common/config/src/main/java/io/helidon/common/config/spi/package-info.java new file mode 100644 index 00000000000..387ce4be611 --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Common Config SPI. + */ +package io.helidon.common.config.spi; diff --git a/common/config/src/main/java/module-info.java b/common/config/src/main/java/module-info.java index 789c2d599f3..86500ceda0f 100644 --- a/common/config/src/main/java/module-info.java +++ b/common/config/src/main/java/module-info.java @@ -18,5 +18,10 @@ * Helidon Common Config Library. */ module io.helidon.common.config { + requires io.helidon.common; + + uses io.helidon.common.config.spi.ConfigProvider; + exports io.helidon.common.config; + exports io.helidon.common.config.spi; } diff --git a/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java b/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java new file mode 100644 index 00000000000..b23b02af85b --- /dev/null +++ b/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java @@ -0,0 +1,46 @@ +/* + * 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.common.config.spi.testsubjects; + +import java.util.Optional; + +import io.helidon.common.config.Config; +import io.helidon.common.config.ConfigValue; +import io.helidon.common.config.spi.ConfigProvider; + +import jakarta.inject.Singleton; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@Singleton +@SuppressWarnings("unchecked") +@Deprecated +public class TestConfigProvider implements ConfigProvider { + + @Override + public Optional __config() { + ConfigValue val = mock(ConfigValue.class); + when(val.get()).thenReturn("mock"); + + Config cfg = mock(Config.class); + when(cfg.asString()).thenReturn(val); + + return Optional.of(cfg); + } + +} diff --git a/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java b/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java new file mode 100644 index 00000000000..077baf6216a --- /dev/null +++ b/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.common.config.test; + +import java.util.Optional; + +import io.helidon.common.config.Config; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.config.ConfigHolder.config; +import static io.helidon.common.config.ConfigHolder.reset; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + +class ConfigHolderTest { + + @Test + void testConfig() { + Optional cfg = config(); + assertThat(cfg.orElseThrow().asString().get(), is("mock")); + + Config mockCfg = mock(Config.class); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> config(mockCfg)); + assertThat(e.getMessage(), + equalTo(Config.class.getSimpleName() + " already set")); + + reset(); + config(mockCfg); + assertThat(config().orElseThrow(), sameInstance(mockCfg)); + } + +} diff --git a/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider b/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider new file mode 100644 index 00000000000..10c33bdb78d --- /dev/null +++ b/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider @@ -0,0 +1,17 @@ +# +# 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. +# + +io.helidon.common.config.spi.testsubjects.TestConfigProvider 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 index 1880666508f..ea462ed895d 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 @@ -728,7 +728,9 @@ List findConfiguredOptionAnnotations(ExecutableElement element /* Method name is camel case (such as maxInitialLineLength) - result is dash separated and lower cased (such as max-initial-line-length) + 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. */ String toConfigKey(String methodName) { StringBuilder result = new StringBuilder(methodName.length() + 5); diff --git a/pico/builder-config/builder-config/README.md b/pico/builder-config/builder-config/README.md new file mode 100644 index 00000000000..0d1b5cf22a9 --- /dev/null +++ b/pico/builder-config/builder-config/README.md @@ -0,0 +1,3 @@ +# pico-builder-config + +This module can be used at compile time and runtime. diff --git a/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml b/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml new file mode 100644 index 00000000000..4b9dc6e150d --- /dev/null +++ b/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/pico/builder-config/builder-config/etc/spotbugs/exclude.xml b/pico/builder-config/builder-config/etc/spotbugs/exclude.xml new file mode 100644 index 00000000000..8bf694d04c5 --- /dev/null +++ b/pico/builder-config/builder-config/etc/spotbugs/exclude.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/pico/builder-config/builder-config/pom.xml b/pico/builder-config/builder-config/pom.xml new file mode 100644 index 00000000000..8918384dd6e --- /dev/null +++ b/pico/builder-config/builder-config/pom.xml @@ -0,0 +1,100 @@ + + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + helidon-pico-builder-config + + Helidon Pico Config Builder API / SPI + + + true + + + + + + + io.helidon.pico.builder + helidon-pico-builder + + + io.helidon.common + helidon-common-config + + + jakarta.inject + jakarta.inject-api + provided + + + io.helidon.config + helidon-config-metadata + provided + + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -XprintProcessorInfo + -XprintRounds + -verbose + + true + + + io.helidon.pico.builder + helidon-pico-builder-processor + ${helidon.version} + + + + + + + diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java new file mode 100644 index 00000000000..ae24ae907a6 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java @@ -0,0 +1,99 @@ +/* + * 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.pico.builder.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import io.helidon.pico.builder.BuilderTrigger; + +/** + * A {@code ConfigBean} is another {@link io.helidon.pico.builder.BuilderTrigger} which extends the + * {@link io.helidon.pico.builder.Builder} concept in support of integration to Helidon's configuration sub-system. It provides + * everything that {@link io.helidon.pico.builder.Builder} provides. However, unlike the base + * {@link io.helidon.pico.builder.Builder} generated classes which can handle any object type, the types used within your target + * {@code ConfigBean}-annotated interface must have all of its attribute getter method types resolvable by Helidon's configuration + * sub-system. + *

+ * One should write a {@code ConfigBean}-annotated interface in such a way as to group the collection of configurable elements + * that logically belong together to then be delivered (and perhaps trigger an activation of) one or more java service types that + * are said to be {@code ConfiguredBy} the given {@link ConfigBean} instance. + *

+ * The {@code pico-builder-config-processor} module is required to be on the APT classpath to code-generate the implementation + * classes for the {@code ConfigBean}. + *

+ * Example: + *

{@code
+ * @ConfigBean
+ * public interface MyConfigBean {
+ *     String getName();
+ *     int getPort();
+ * }
+ * }
+ *

+ * When {@code Pico} services and config-service modules are incorporated into the application lifecycle, the configuration + * sub-system is scanned at startup and {@code ConfigBean} instances are created and fed into the {@code ConfigBeanRegistry}. + * This mapping occurs based upon the {@link io.helidon.config.metadata.ConfiguredOption#key()} applied on the {@code ConfigBean} + * interface type. If no such declaration is found, then the type name is used as the key (e.g., MyConfigBean would map to + * "my-config-bean"). + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(java.lang.annotation.ElementType.TYPE) +@BuilderTrigger +public @interface ConfigBean { + + /** + * Determines whether an instance of this config bean in the bean registry will result in the backing service + * {@code ConfiguredBy} this bean to be activated. + * + * @return true if this config bean should drive {@code ConfiguredBy} service activation + */ + boolean drivesActivation() default true; + + /** + * An instance of this bean will be created if there are no instances discovered by the configuration provider(s) post + * startup, and will use all default values annotated using {@code ConfiguredOptions} from the bean interface methods. + * + * @return the default config bean instance using defaults + */ + boolean atLeastOne() default false; + + /** + * Determines whether there can be more than one bean instance of this type. + *

+ * If false then only 0..1 behavior will be permissible for active beans in the config registry. If true then {@code > 1} + * instances will be permitted. The default values is {@code true}. + *

+ * Note: this attribute is dynamic in nature, and therefore cannot be validated at compile time. All violations found to this + * policy will be observed during PicoServices activation. + * + * @return true if repeatable + */ + boolean repeatable() default true; + + /** + * The overridden key to use. If not set this will default to use the expanded name from the config subsystem, + * (e.g. MyConfig -> "my-config"). + * + * @return the overriding key to use + */ + String key() default ""; + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java new file mode 100644 index 00000000000..bf8cfa090f8 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Helidon Pico Config Builder API. + */ +package io.helidon.pico.builder.config; diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java new file mode 100644 index 00000000000..9d0a38d42a7 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java @@ -0,0 +1,192 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +import io.helidon.pico.builder.AttributeVisitor; + +/** + * Validates a {@link io.helidon.pico.builder.config.ConfigBean} generated builder type instance bean the builder build() is + * called and the result is consumed. + * + * @param the config bean builder type + */ +@FunctionalInterface +public interface ConfigBeanBuilderValidator { + + /** + * Creates a validation round for all the config bean attributes of the provided config bean. + * + * @param builder the config builder instance + * @param configBeanBuilderType the config bean type + * @return the validation round that can be used for attribute level validation + */ + ValidationRound createValidationRound(CBB builder, + Class configBeanBuilderType); + + + /** + * The validation issue severity level. + * @see ConfigBeanBuilderValidator.ValidationIssue#getSeverity() + */ + enum Severity { + + /** + * A warning level. + */ + WARNING, + + /** + * An error level. + */ + ERROR + + } + + + /** + * Represents a single round of validation. A single round of validation will iterate over each attributes of the + * config bean, calling {@link #validate(String, Supplier, Class, java.util.Map)} for each attribute. + */ + interface ValidationRound extends AttributeVisitor { + + /** + * All the issues found. + * + * @return all issues found + */ + List getIssues(); + + /** + * Returns true if there were any issues found including warnings or errors. + * + * @return true if any issues were found + */ + default boolean hasIssues() { + return !getIssues().isEmpty(); + } + + /** + * Returns true if any errors were found. + * + * @return true if any issues were found of type {@link ConfigBeanBuilderValidator.Severity#ERROR} + */ + default boolean hasErrors() { + return getIssues().stream().anyMatch(it -> it.getSeverity() == Severity.ERROR); + } + + /** + * Returns true if the validation round is completed. + * + * @return true if the validation round is completed + * @see #finish(boolean) + */ + boolean isCompleted(); + + /** + * Performs a validation for a single attribute. + * + * @param attributeName the attribute name being validated + * @param valueSupplier the value supplier for the attribute + * @param meta the meta attributes for this attribute type + * @param cbType the attribute type + * @return the validation round continuation as a fluent-builder + */ + ValidationRound validate(String attributeName, Supplier valueSupplier, Class cbType, Map meta); + + @Override + default void visit(String attributeName, + Supplier valueSupplier, + Map meta, + Object userDefinedCtx, + Class cbType, + Class... ignored) { + validate(attributeName, valueSupplier, cbType, meta); + } + + /** + * Finishes the validation round, and will optionally throw a runtime exception if any error issues were found. + * + * @param throwIfErrors flag to indicate whether an exception should be raised if any errors were found + * @return the fluent builder for this round + * @throws java.lang.IllegalStateException if there were any validation errors in the round + */ + ValidationRound finish(boolean throwIfErrors); + } + + + /** + * Represents an issue that was encountered during + * {@link ValidationRound#validate(String, java.util.function.Supplier, Class, java.util.Map)}. + */ + class ValidationIssue { + private final Severity severity; + private final String attributeName; + private final String message; + + /** + * Constructs a new validation issue. + * + * @param severity the severity + * @param attributeName the attribute name in question + * @param message the message + */ + public ValidationIssue(Severity severity, String attributeName, String message) { + this.severity = Objects.requireNonNull(severity); + this.attributeName = Objects.requireNonNull(attributeName); + this.message = Objects.requireNonNull(message); + } + + /** + * Return the severity. + * + * @return the severity + */ + public Severity getSeverity() { + return severity; + } + + /** + * Returns the attribute name in question. + * + * @return the attribute name + */ + public String getAttributeName() { + return attributeName; + } + + /** + * Returns the user-friendly message. + * + * @return the user-friendly message + */ + public String getMessage() { + return message; + } + + @Override + public String toString() { + return getMessage(); + } + + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java new file mode 100644 index 00000000000..8072d6430b3 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java @@ -0,0 +1,68 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link ConfigBeanBuilderValidator}. + * + * @see ConfigBeanBuilderValidatorProvider + */ +public class ConfigBeanBuilderValidatorHolder { + private static final LazyValue>> INSTANCE = + LazyValue.create(ConfigBeanBuilderValidatorHolder::load); + + private ConfigBeanBuilderValidatorHolder() { + } + + /** + * Provides the global service-loader instance of {@link ConfigBeanBuilderValidator}. + *

+ * Note that the current expectation here is that the global instance is capable for validating any + * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. The parameter used for the configBeanBuilderType serves + * to both type case the validator, and also reserves the possibility that the returned instance may be nuanced per builder + * type at some point in the future. + * + * @param configBeanBuilderType the config bean builder type to validate + * @param the config bean builder type + * @return the config bean builder validator + */ + @SuppressWarnings({"rawTypes", "unchecked"}) + public static Optional> configBeanValidatorFor(Class configBeanBuilderType) { + return (Optional) INSTANCE.get(); + } + + private static Optional> load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigBeanBuilderValidatorProvider.class, + ConfigBeanBuilderValidatorProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().configBeanBuilderValidator()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java new file mode 100644 index 00000000000..ece42d72d74 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link ConfigBeanBuilderValidator} instance. + * + * @see ConfigBeanBuilderValidatorHolder + */ +public interface ConfigBeanBuilderValidatorProvider { + + /** + * The service-loaded global {@link ConfigBeanBuilderValidator} instance. + * + * @return the global config bean builder validator instance + */ + ConfigBeanBuilderValidator configBeanBuilderValidator(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java new file mode 100644 index 00000000000..aa03bd9d607 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java @@ -0,0 +1,81 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Objects; + +import io.helidon.pico.builder.Builder; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * Represents all the attributes belonging to {@link io.helidon.pico.builder.config.ConfigBean} available in a + * {@link io.helidon.pico.builder.Builder} style usage pattern. + */ +@Builder(implPrefix = "Meta") +public interface ConfigBeanInfo extends ConfigBean { + + /** + * Builds meta information appropriate for config integration from a + * {@link io.helidon.pico.builder.config.ConfigBean} instance. This will use the key if {@link #key()} is present, and + * if not present will default to the simple class name of the bean type. + * + * @param val the config bean instance + * @param cfgBeanType the config bean type + * @return the meta information for the config bean + */ + static MetaConfigBeanInfo toMetaConfigBeanInfo(ConfigBean val, + Class cfgBeanType) { + Objects.requireNonNull(cfgBeanType); + MetaConfigBeanInfo.Builder builder = MetaConfigBeanInfo.toBuilder(Objects.requireNonNull(val)); + String key = val.key(); + if (!key.isBlank()) { + builder.key(toConfigKey(cfgBeanType.getSimpleName())); + } + return builder.build(); + } + + /** + * Converts the name (i.e., simple class name or method name) into a config key. + *

+ * Method name is camel case (such as maxInitialLineLength) + * result is dash separated and lower cased (such as max-initial-line-length). + * + * @param name the input name + * @return the config key + */ + // note: this method is also found in ConfigMetadataHandler. + static String toConfigKey(String name) { + StringBuilder result = new StringBuilder(name.length() + 5); + + char[] chars = name.toCharArray(); + for (char aChar : chars) { + if (Character.isUpperCase(aChar)) { + if (result.length() == 0) { + result.append(Character.toLowerCase(aChar)); + } else { + result.append('-') + .append(Character.toLowerCase(aChar)); + } + } else { + result.append(aChar); + } + } + + return result.toString(); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java new file mode 100644 index 00000000000..a71e423257d --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java @@ -0,0 +1,40 @@ +/* + * 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.pico.builder.config.spi; + +import io.helidon.common.config.Config; + +/** + * Maps a {@link io.helidon.common.config.Config} instance to a newly created + * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type instance. + * + * @param the config bean type + */ +@FunctionalInterface +public interface ConfigBeanMapper { + + /** + * Translate the provided configuration into the appropriate config bean for this service type. + * + * @param cfg the config + * @param configBeanType the config bean type + * @return the config bean generated + */ + CB toConfigBean(Config cfg, + Class configBeanType); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java new file mode 100644 index 00000000000..f287390a360 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java @@ -0,0 +1,66 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link ConfigBeanMapper}. + * + * @see ConfigBeanMapperProvider + */ +public class ConfigBeanMapperHolder { + private static final LazyValue>> INSTANCE = LazyValue.create(ConfigBeanMapperHolder::load); + + private ConfigBeanMapperHolder() { + } + + /** + * Provides the global service-loader instance of {@link ConfigBeanMapper}. + *

+ * Note that the current expectation here is that the global instance is capable for mapping any + * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. The parameter used for the configBeanType serves + * to both type case the mapper, and also reserves the possibility that the returned instance may be nuanced per bean + * type at some point in the future. + * + * @param configBeanType the config bean type to map + * @param the config bean type + * @return the config bean mapper + */ + @SuppressWarnings({"rawTypes", "unchecked"}) + public static Optional> configBeanMapperFor(Class configBeanType) { + return (Optional) INSTANCE.get(); + } + + private static Optional> load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigBeanMapperProvider.class, ConfigBeanMapperProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().configBeanMapper()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java new file mode 100644 index 00000000000..eac42ff3c4d --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link ConfigBeanMapper} instance. + * + * @see ConfigBeanMapperHolder + */ +public interface ConfigBeanMapperProvider { + + /** + * The service-loaded global {@link ConfigBeanMapper} instance. + * + * @return the global config bean mapper instance + */ + ConfigBeanMapper configBeanMapper(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java new file mode 100644 index 00000000000..bd9d0fd9b81 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java @@ -0,0 +1,71 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +/** + * Contract for resolving a configuration builder attribute element to the backing {@link io.helidon.common.config.Config}. + */ +public interface ConfigResolver { + + /** + * Resolves a {@link io.helidon.pico.builder.config.ConfigBean} singular element value from the + * backing {@link io.helidon.common.config.Config}. + * + * @param ctx the resolution context + * @param meta the meta attributes for this config bean + * @param request the request + * @param the attribute value type being resolved in the request + * @return the resolved value or empty if unable to resolve the request + */ + Optional of(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request); + + /** + * Resolves a {@link io.helidon.pico.builder.config.ConfigBean} collection-like element value from the + * backing {@link io.helidon.common.config.Config}. + * + * @param ctx the resolution context + * @param meta the meta attributes for this config bean + * @param request the request + * @param the attribute value type being resolved in the request + * @return the resolved value or empty if unable to resolve the request + */ + Optional> ofCollection(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request); + + /** + * Resolves a {@link io.helidon.pico.builder.config.ConfigBean} map-like element value from the + * backing {@link io.helidon.common.config.Config}. + * + * @param ctx the resolution context + * @param meta the meta attributes for this config bean + * @param request the request + * @param the map attribute key type being resolved in the request + * @param the map attribute value type being resolved in the request + * @return the resolved value or empty if unable to resolve the request + */ + Optional> ofMap(ResolutionCtx ctx, + Map> meta, + ConfigResolverMapRequest request); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java new file mode 100644 index 00000000000..d71ec21bd0a --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java @@ -0,0 +1,58 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link ConfigResolver}. + * + * @see ConfigResolverProvider + */ +public class ConfigResolverHolder { + private static final LazyValue> INSTANCE = LazyValue.create(ConfigResolverHolder::load); + + private ConfigResolverHolder() { + } + + /** + * Provides the global service-loader instance of {@link ConfigResolver}. + * + * @return the config resolver + */ + public static Optional configResolver() { + return INSTANCE.get(); + } + + private static Optional load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigResolverProvider.class, ConfigResolverProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().configResolver()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java new file mode 100644 index 00000000000..b1b12ff1b7d --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java @@ -0,0 +1,48 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * An extension of {@link io.helidon.pico.builder.config.spi.ConfigResolverRequest} for handling {@link java.util.Map}-like + * requests into {@link io.helidon.pico.builder.config.spi.ConfigResolver}. + * + * @param the key type + * @param the value type + */ +@Builder +public interface ConfigResolverMapRequest extends ConfigResolverRequest { + + /** + * The key type of the map attribute. + * + * @return the key type of the map attribute + */ + Class keyType(); + + /** + * The generic component type of the {@link #keyType()}. For example, this would be "String" for + * {@code Optional}. + * + * @return the component type + */ + Optional> keyComponentType(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java new file mode 100644 index 00000000000..bc37b31eca9 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java @@ -0,0 +1,31 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface to find implementation of {@link ConfigResolver}. + */ +public interface ConfigResolverProvider { + + /** + * Provide the {@link ConfigResolver} implementation. + * + * @return config resolver + */ + ConfigResolver configResolver(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java new file mode 100644 index 00000000000..4c200077b3f --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java @@ -0,0 +1,60 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * Used in conjunction with {@link io.helidon.pico.builder.config.spi.ConfigResolver}. + * + * @param the attribute value type being resolved + */ +@Builder +public interface ConfigResolverRequest { + + /** + * The configuration key. + * + * @return the optional configuration key + */ + String configKey(); + + /** + * The config builder attribute name - which is typically the same as the method name. + * + * @return the config builder attribute name + */ + String attributeName(); + + /** + * The type of the attribute value. + * + * @return the type of the attribute value + */ + Class valueType(); + + /** + * The generic component type of the {@link #valueType()}. For example, this would be "String" for + * {@code Optional}. + * + * @return the value component type + */ + Optional> valueComponentType(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java new file mode 100644 index 00000000000..f2841c03157 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java @@ -0,0 +1,120 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +import io.helidon.common.Weight; +import io.helidon.common.Weighted; +import io.helidon.common.config.Config; +import io.helidon.common.config.ConfigValue; + +import jakarta.inject.Singleton; + +/** + * The default implementation of {@link ConfigResolver} simply resolves against {@link io.helidon.common.config.Config} directly. + */ +@Singleton +@Weight(Weighted.DEFAULT_WEIGHT - 1) +public class DefaultConfigResolver implements ConfigResolver, ConfigResolverProvider { + + /** + * Tag that represents meta information about the attribute. Used in the maps for various methods herein. + */ + public static final String TAG_META = "__meta"; + + /** + * Default constructor, service loader invoked. + */ + @Deprecated + public DefaultConfigResolver() { + } + + @Override + public ConfigResolver configResolver() { + return this; + } + + @Override + public Optional of(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request) { + Config attrCfg = ctx.config().get(request.configKey()); + return attrCfg.exists() + ? optionalWrappedConfig(attrCfg, meta, request) : Optional.empty(); + } + + @Override + @SuppressWarnings("unchecked") + public Optional> ofCollection(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request) { + Config attrCfg = ctx.config().get(request.configKey()); + return attrCfg.exists() + ? (Optional>) optionalWrappedConfig(attrCfg, meta, request) : Optional.empty(); + } + + @Override + @SuppressWarnings("unchecked") + public Optional> ofMap(ResolutionCtx ctx, + Map> meta, + ConfigResolverMapRequest request) { + Config attrCfg = ctx.config().get(request.configKey()); + return attrCfg.exists() + ? (Optional>) optionalWrappedConfig(attrCfg, meta, request) : Optional.empty(); + } + + @SuppressWarnings("unchecked") + private Optional optionalWrappedConfig(Config attrCfg, + Map> meta, + ConfigResolverRequest request) { + Class componentType = request.valueComponentType().orElse(null); + Class type = request.valueType(); + final boolean isOptional = Optional.class.equals(type); + if (isOptional) { + type = request.valueComponentType().orElseThrow(); + } + final boolean isCharArray = (type.isArray() && char.class == type.getComponentType()); + if (isCharArray) { + type = String.class; + } + + try { + ConfigValue attrVal = attrCfg.as(type); + Object val = attrVal.get(); + if (isCharArray) { + val = ((String) val).toCharArray(); + } + + return Optional.of(isOptional ? (T) Optional.of(val) : (T) val); + } catch (Exception e) { + String typeName = toTypeNameDescription(request.valueType(), componentType); + String configKey = attrCfg.key().toString(); + throw new IllegalStateException("Failed to convert " + typeName + + " for attribute: " + request.attributeName() + + " and config key: " + configKey, e); + } + } + + private static String toTypeNameDescription(Class type, + Class componentType) { + return type.getTypeName() + "<" + componentType.getTypeName() + ">"; + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java new file mode 100644 index 00000000000..5fd2849c017 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java @@ -0,0 +1,48 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Reserved for internal use! + *

+ * Every {@link io.helidon.pico.builder.config.ConfigBean}-annotated type will also implement this contract. + * + * @deprecated this is for internal use only + */ +public interface GeneratedConfigBean extends GeneratedConfigCommon { + +/* + Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated + methods. If its necessary to have a 0 or 1-arg method then the convention of prefixing the method with two underscores should be + used. + */ + + /** + * Set the instance id of this config bean. + * + * @param val the new instance identifier + */ + void __instanceId(String val); + + /** + * Returns the existing instance identifier. + * + * @return the instance identifier + */ + String __instanceId(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java new file mode 100644 index 00000000000..9c07c600b79 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java @@ -0,0 +1,71 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Objects; +import java.util.Optional; + +import io.helidon.common.config.Config; + +/** + * Minimal implementation for the {@link GeneratedConfigCommon}. This is the base for generated config beans. + * + * @deprecated this is for internal use only + */ +public abstract class GeneratedConfigBeanBase implements GeneratedConfigCommon { + private Config cfg; + private String instanceId; + + /** + * Protected constructor for initializing the generated config bean instance variables. + */ + protected GeneratedConfigBeanBase() { + } + + @Override + public Optional __config() { + return Optional.ofNullable(cfg); + } + + /** + * Sets the config instance. + * + * @param cfg the config instance + */ + public void __config(Config cfg) { + this.cfg = Objects.requireNonNull(cfg); + } + + /** + * Returns the instance id assigned to this bean. + * + * @return the instance id assigned to this bean + */ + public String __instanceId() { + return instanceId; + } + + /** + * Assigns the instance id assigned to this bean. + * + * @param val the new instance id for this bean + */ + public void __instanceId(String val) { + instanceId = val; + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java new file mode 100644 index 00000000000..e1e302d1709 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java @@ -0,0 +1,61 @@ +/* + * 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.pico.builder.config.spi; + +import io.helidon.common.config.Config; + +/** + * Reserved for internal use! + *

+ * Every {@link io.helidon.pico.builder.config.ConfigBean}-annotated type will also implement this contract. + * + * @deprecated + */ +public interface GeneratedConfigBeanBuilder extends GeneratedConfigCommon { + +/* + Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated + methods. If its necessary to have a 0 or 1-arg method then the convention of prefixing the method with two underscores should be + used. + */ + + /** + * Copy values from the config, optionally applying the default resolver and validator. + * + * @param cfg the config to initialize the builder values + * @param resolveAndValidate if called will resolve and validate + * + * @see ConfigResolver + * @see ConfigBeanBuilderValidatorHolder + * @throws java.lang.IllegalStateException if there are any resolution or validation errors + */ + void acceptConfig(Config cfg, + boolean resolveAndValidate); + + /** + * Copy values from an existing builder. + * + * @param cfg the config to initialize the builder values + * @param resolver the resolver + * @param validator the validator + * @throws java.lang.IllegalStateException if there are any resolution or validation errors + */ + void acceptConfig(Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java new file mode 100644 index 00000000000..ad31a26f906 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java @@ -0,0 +1,73 @@ +/* + * 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.pico.builder.config.spi; + +import io.helidon.common.config.Config; + +/** + * Minimal implementation for the {@link GeneratedConfigBeanBuilder}. + * + * @deprecated this is for internal use only + */ +public abstract class GeneratedConfigBeanBuilderBase extends GeneratedConfigBeanBase implements GeneratedConfigBeanBuilder { + + /** + * Default constructor. Reserved for internal use. + */ + protected GeneratedConfigBeanBuilderBase() { + } + + @Override + public void acceptConfig(Config cfg, + boolean resolveAndValidate) { + if (resolveAndValidate) { + // note: do not simplify this code by calling createResolutionContext - we want that to come from the generated code + acceptConfig(cfg, + ConfigResolverHolder.configResolver().get(), + ConfigBeanBuilderValidatorHolder.configBeanValidatorFor(__configBeanType()).orElse(null)); + } else { + __config(cfg); + } + } + + /** + * Creates a resolution context. + * + * @param configBeanType the config bean type + * @param cfg the config + * @param resolver the resolver + * @param validator the config bean builder validator + * @return the resolution context + */ + protected ResolutionCtx createResolutionContext(Class configBeanType, + Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator) { + // note to self: that in the future we should probably accept a code-generated 'version id' here --jtrent + return ResolutionCtx.create(configBeanType, cfg, resolver, validator); + } + + /** + * Called when finished the resolution process. + * + * @param ctx the resolution context + */ + protected void finishedResolution(ResolutionCtx ctx) { + // note to self: need to add validation here --jtrent + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java new file mode 100644 index 00000000000..7fb8dd030a6 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java @@ -0,0 +1,62 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +import io.helidon.common.config.Config; +import io.helidon.common.config.spi.ConfigProvider; +import io.helidon.pico.builder.AttributeVisitor; + +/** + * These methods are in common between generated config bean and config bean builder types. + * + * @deprecated this is for internal use only + */ +public interface GeneratedConfigCommon extends ConfigProvider { + +/* + Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated + methods. If its necessary to have a 0 or 1-arg method then the convention of prefixing the method with two underscores should be + used. + */ + + /** + * Returns the configuration assigned to the generated config bean. + * + * @return the configuration assigned + */ + @Override + Optional __config(); + + /** + * Returns the {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. + * + * @return the config bean type + */ + Class __configBeanType(); + + /** + * Visits all attributes with the provided {@link io.helidon.pico.builder.AttributeVisitor}. + * + * @param visitor the visitor + * @param userDefinedCtx any user-defined context + */ + void visitAttributes(AttributeVisitor visitor, + Object userDefinedCtx); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java new file mode 100644 index 00000000000..618ef1a2290 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java @@ -0,0 +1,187 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Objects; +import java.util.Optional; + +import io.helidon.common.config.Config; + +/** + * Config resolution process context. + */ +public class ResolutionCtx { + private final Class configBeanType; + private final Config cfg; + private final ConfigResolver resolver; + private final ConfigBeanBuilderValidator validator; + + /** + * Constructor for this type that takes a builder. + * + * @param b the builder + */ + protected ResolutionCtx(Builder b) { + this.configBeanType = Objects.requireNonNull(b.configBeanType); + this.cfg = Objects.requireNonNull(b.cfg); + this.resolver = Objects.requireNonNull(b.resolver); + this.validator = b.validator; + } + + /** + * Return the config bean type. + * + * @return the config bean type + */ + public Class configBeanType() { + return configBeanType; + } + + /** + * Return the config. + * + * @return the config + */ + public Config config() { + return cfg; + } + + /** + * Return the config resolver. + * + * @return the resolver + */ + public ConfigResolver resolver() { + return resolver; + } + + /** + * Return the config bean builder validator. + * + * @return the validator + */ + public Optional> validator() { + return Optional.ofNullable(validator); + } + + @Override + public String toString() { + return config().toString(); + } + + /** + * Creates a new fluent builder for this type. + * + * @return a fluent builder + */ + public static Builder builder() { + return new Builder(); + } + + + /** + * Creates a resolution context from the provided arguments. + * + * @param configBeanType the config bean type + * @param cfg the config + * @param resolver the resolver + * @param validator the bean builder validator + * @return the resolution context + */ + public static ResolutionCtx create(Class configBeanType, + Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator) { + return ResolutionCtx.builder() + .configBeanType(configBeanType) + .config(cfg) + .resolver(resolver) + .validator(validator) + .build(); + } + + /** + * Fluent builder for {@link io.helidon.pico.builder.config.spi.ResolutionCtx}. + */ + public static class Builder implements io.helidon.common.Builder { + private Class configBeanType; + private Config cfg; + private ConfigResolver resolver; + private ConfigBeanBuilderValidator validator; + + /** + * Constructor for the fluent builder. + */ + protected Builder() { + } + + /** + * Build the instance. + * + * @return the built instance + */ + @Override + public ResolutionCtx build() { + return new ResolutionCtx(this); + } + + /** + * Set the config bean type. + * + * @param configBeanType the config bean type + * @return this fluent builder + */ + public Builder configBeanType(Class configBeanType) { + this.configBeanType = Objects.requireNonNull(configBeanType); + return this; + } + + /** + * Set the config. + * + * @param val the config + * @return this fluent builder + */ + public Builder config(Config val) { + this.cfg = Objects.requireNonNull(val); + return identity(); + } + + /** + * Set the config resolver. + * + * @param val the config resolver + * @return this fluent builder + */ + public Builder resolver(ConfigResolver val) { + this.resolver = Objects.requireNonNull(val); + return identity(); + } + + /** + * Set the config bean builder validator. + * + * @param val the config validator + * @return this fluent builder + */ + public Builder validator(ConfigBeanBuilderValidator val) { + this.validator = val; + return identity(); + } + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java new file mode 100644 index 00000000000..03bfe6d5d19 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java @@ -0,0 +1,39 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +/** + * String value parser. + */ +@FunctionalInterface +public interface StringValueParser { + + /** + * Parse the string into a type R instance. + * + * @param val the string value to parse + * @param type the type of the result expected + * @param the return type + * @return the optional nullable parsed value + * @throws java.lang.IllegalArgumentException if the format is not parsable or the return type is not supported + */ + Optional parse(String val, + Class type); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java new file mode 100644 index 00000000000..9c388f21e60 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java @@ -0,0 +1,58 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link StringValueParser}. + * + * @see StringValueParserProvider + */ +public class StringValueParserHolder { + private static final LazyValue> INSTANCE = LazyValue.create(StringValueParserHolder::load); + + private StringValueParserHolder() { + } + + /** + * Provides the global service-loader instance of {@link StringValueParser}. + * + * @return the string value parser + */ + public static Optional stringValueParser() { + return INSTANCE.get(); + } + + private static Optional load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(StringValueParserProvider.class, StringValueParserProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().stringValueParser()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java new file mode 100644 index 00000000000..31ec291e252 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link StringValueParser} instance. + * + * @see io.helidon.pico.builder.config.spi.StringValueParserHolder + */ +public interface StringValueParserProvider { + + /** + * The service-loaded global {@link StringValueParser} instance. + * + * @return the global string value parser instance + */ + StringValueParser stringValueParser(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java new file mode 100644 index 00000000000..dbf48f19b7e --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Helidon Pico Config Builder SPI. + */ +package io.helidon.pico.builder.config.spi; diff --git a/pico/builder-config/builder-config/src/main/java/module-info.java b/pico/builder-config/builder-config/src/main/java/module-info.java new file mode 100644 index 00000000000..67c804cda28 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/module-info.java @@ -0,0 +1,36 @@ +/* + * 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 Helidon Pico Config Builder API / SPI + */ +module io.helidon.pico.builder.config { + requires static jakarta.inject; + requires io.helidon.pico.builder; + requires io.helidon.common; + requires io.helidon.common.config; + + uses io.helidon.pico.builder.config.spi.ConfigBeanMapperProvider; + uses io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidatorProvider; + uses io.helidon.pico.builder.config.spi.ConfigResolverProvider; + uses io.helidon.pico.builder.config.spi.StringValueParserProvider; + + exports io.helidon.pico.builder.config; + exports io.helidon.pico.builder.config.spi; + + provides io.helidon.pico.builder.config.spi.ConfigResolverProvider + with io.helidon.pico.builder.config.spi.DefaultConfigResolver; +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java new file mode 100644 index 00000000000..0159d448ed7 --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.ConfigBeanMapperHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class ConfigBeanMapperHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(ConfigBeanMapperHolder.configBeanMapperFor(Object.class), + is(optionalEmpty())); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java new file mode 100644 index 00000000000..c39c20c2554 --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidatorHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class ConfigBuilderValidatorHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(ConfigBeanBuilderValidatorHolder.configBeanValidatorFor(Object.class), + is(optionalEmpty())); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java new file mode 100644 index 00000000000..27f6ef116da --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.ConfigResolverHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalPresent; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class ConfigResolverHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(ConfigResolverHolder.configResolver(), + is(optionalPresent())); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java new file mode 100644 index 00000000000..e473fb1602f --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java @@ -0,0 +1,55 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.spi.ConfigBeanInfo; +import io.helidon.pico.builder.config.spi.MetaConfigBeanInfo; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@ConfigBean() +class MetaConfigBeanInfoTest { + + @Test + void testToMetaConfigBeanInfo() { + ConfigBean cfg = getClass().getAnnotation(ConfigBean.class); + assertNotNull(cfg); + MetaConfigBeanInfo metaCfg = ConfigBeanInfo.toMetaConfigBeanInfo(cfg, ConfigBean.class); + assertThat(metaCfg.annotationType(), sameInstance(ConfigBean.class)); + assertThat(metaCfg.repeatable(), is(true)); + assertThat(metaCfg.drivesActivation(), is(true)); + assertThat(metaCfg.atLeastOne(), is(false)); + assertThat(metaCfg.key(), is("")); + } + + @Test + void testToConfigKey() { + assertAll( + () -> assertThat(ConfigBeanInfo.toConfigKey("maxInitialLineLength"), is("max-initial-line-length")), + () -> assertThat(ConfigBeanInfo.toConfigKey("port"), is("port")), + () -> assertThat(ConfigBeanInfo.toConfigKey("listenAddress"), is("listen-address")) + ); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java new file mode 100644 index 00000000000..20586ad83f0 --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.StringValueParserHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class StringValueParserHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(StringValueParserHolder.stringValueParser(), + is(optionalEmpty())); + } + +} diff --git a/pico/builder-config/pom.xml b/pico/builder-config/pom.xml new file mode 100644 index 00000000000..f5a7de0346e --- /dev/null +++ b/pico/builder-config/pom.xml @@ -0,0 +1,42 @@ + + + + + + io.helidon.pico + helidon-pico-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + Helidon Pico Builder Config Project + pom + + + builder-config + processor + tests + + + diff --git a/pico/builder-config/processor/README.md b/pico/builder-config/processor/README.md new file mode 100644 index 00000000000..6d743bf762d --- /dev/null +++ b/pico/builder-config/processor/README.md @@ -0,0 +1,3 @@ +# pico-builder-config-processor + +This module should typically should be used at compile-time on the APt classpath. Also note that even though it is called processor it is not technically a processor, but rather a BuilderCreator extension to the base Builder processor. diff --git a/pico/builder-config/processor/pom.xml b/pico/builder-config/processor/pom.xml new file mode 100644 index 00000000000..b5edbd42e46 --- /dev/null +++ b/pico/builder-config/processor/pom.xml @@ -0,0 +1,78 @@ + + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + helidon-pico-builder-config-processor + + Helidon Pico Builder ConfigBean Processor + + + + io.helidon.pico.builder.config + helidon-pico-builder-config + + + io.helidon.pico.builder + helidon-pico-builder-processor + + + io.helidon.pico + helidon-pico-types + + + io.helidon.pico + helidon-pico + + + io.helidon.common + helidon-common-config + + + jakarta.inject + jakarta.inject-api + compile + + + jakarta.annotation + jakarta.annotation-api + provided + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java new file mode 100644 index 00000000000..65394f33cd6 --- /dev/null +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java @@ -0,0 +1,389 @@ +/* + * 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.pico.builder.config.processor.tools; + +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +import io.helidon.common.Weight; +import io.helidon.common.Weighted; +import io.helidon.common.config.Config; +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.Contract; +import io.helidon.pico.ExternalContracts; +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidator; +import io.helidon.pico.builder.config.spi.ConfigBeanInfo; +import io.helidon.pico.builder.config.spi.ConfigResolver; +import io.helidon.pico.builder.config.spi.DefaultConfigResolverRequest; +import io.helidon.pico.builder.config.spi.GeneratedConfigBeanBase; +import io.helidon.pico.builder.config.spi.GeneratedConfigBeanBuilderBase; +import io.helidon.pico.builder.config.spi.MetaConfigBeanInfo; +import io.helidon.pico.builder.config.spi.ResolutionCtx; +import io.helidon.pico.builder.processor.spi.TypeInfo; +import io.helidon.pico.builder.processor.tools.BodyContext; +import io.helidon.pico.builder.processor.tools.DefaultBuilderCreator; +import io.helidon.pico.types.AnnotationAndValue; +import io.helidon.pico.types.DefaultAnnotationAndValue; +import io.helidon.pico.types.DefaultTypeName; +import io.helidon.pico.types.TypeName; +import io.helidon.pico.types.TypedElementName; + +/** + * A specialization of {@link DefaultBuilderCreator} that supports the additional add-ons to the builder generated classes that + * binds to the config sub-system. + * + * @see io.helidon.pico.builder.config.spi.GeneratedConfigBean + * @see io.helidon.pico.builder.config.spi.GeneratedConfigBeanBuilder + */ +@Weight(Weighted.DEFAULT_WEIGHT) +public class ConfigBeanBuilderCreator extends DefaultBuilderCreator { + + /** + * Default constructor. + */ + // note: this needs to remain public since it will be resolved via service loader ... + @Deprecated + public ConfigBeanBuilderCreator() { + } + + @Override + public Set> supportedAnnotationTypes() { + return Collections.singleton(ConfigBean.class); + } + + @Override + protected void preValidate(TypeName implTypeName, + TypeInfo typeInfo, + AnnotationAndValue builderAnnotation) { + assertNoAnnotation(Contract.class.getName(), typeInfo); + assertNoAnnotation(ExternalContracts.class.getName(), typeInfo); + // note to self: add this when ConfiguredBy is introduced --jtrent +// assertNoAnnotation(ConfiguredBy.class.getName(), typeInfo); + assertNoAnnotation(jakarta.inject.Singleton.class.getName(), typeInfo); + assertNoAnnotation("javax.inject.Singleton", typeInfo); + } + + @Override + protected Optional baseExtendsTypeName(BodyContext ctx) { + return Optional.of(DefaultTypeName.create(GeneratedConfigBeanBase.class)); + } + + @Override + protected Optional baseExtendsBuilderTypeName(BodyContext ctx) { + return Optional.of(DefaultTypeName.create(GeneratedConfigBeanBuilderBase.class)); + } + + @Override + protected String instanceIdRef(BodyContext ctx) { + return "__instanceId()"; + } + + @Override + protected void appendExtraImports(StringBuilder builder, + BodyContext ctx) { + builder.append("\nimport ").append(AtomicInteger.class.getName()).append(";\n"); + builder.append("import ").append(Optional.class.getName()).append(";\n"); + builder.append("import ").append(Supplier.class.getName()).append(";\n\n"); + + super.appendExtraImports(builder, ctx); + + builder.append("import ").append(Config.class.getName()).append(";\n"); + builder.append("import ").append(ConfigResolver.class.getName()).append(";\n"); + builder.append("import ").append(ConfigBeanBuilderValidator.class.getName()).append(";\n"); + } + + @Override + protected void appendMetaAttributes(StringBuilder builder, + BodyContext ctx) { + if (ctx.doingConcreteType()) { + super.appendMetaAttributes(builder, ctx); + return; + } + + builder.append("\t@Override\n"); + builder.append("\tpublic Class __configBeanType() {\n" + + "\t\treturn ").append(ctx.typeInfo().typeName().name()).append(".class;\n" + + "\t}\n\n"); + javaDocMetaAttributesGetter(builder); + builder.append("\tpublic static Class __thisConfigBeanType() {\n" + + "\t\treturn ").append(ctx.typeInfo().typeName().name()).append(".class;\n" + + "\t}\n\n"); + + super.appendMetaAttributes(builder, ctx); + } + + @Override + protected void appendMetaProps(StringBuilder builder, + BodyContext ctx, + String tag, + AtomicBoolean needsCustomMapOf) { + builder.append("\t\t").append(tag); + builder.append(".put(\"__meta\", Map.of(").append(ConfigBeanInfo.class.getName()); + builder.append(".class.getName(),\n\t\t\t\t").append(MetaConfigBeanInfo.class.getName()).append(".builder()\n"); + appendConfigBeanInfoAttributes(builder, + ctx.typeInfo(), + DefaultAnnotationAndValue + .findFirst(ConfigBean.class.getTypeName(), + ctx.typeInfo().annotations()).orElseThrow()); + builder.append("\t\t\t\t\t\t.build()));\n"); + super.appendMetaProps(builder, ctx, tag, needsCustomMapOf); + } + + @Override + protected void appendExtraFields(StringBuilder builder, + BodyContext ctx) { + super.appendExtraFields(builder, ctx); + if (!ctx.hasParent() && !ctx.doingConcreteType()) { + builder.append("\tprivate static final AtomicInteger __INSTANCE_ID = new AtomicInteger();\n"); + } + } + + @Override + protected void appendExtraCtorCode(StringBuilder builder, + BodyContext ctx, + String builderTag) { + if (!ctx.hasParent()) { + builder.append("\t\t__instanceId(String.valueOf(__INSTANCE_ID.getAndIncrement()));\n"); + builder.append("\t\tif (b.__config().isPresent()) {\n" + + "\t\t\t__config(").append(builderTag).append(".__config().get());\n" + + "\t\t}\n"); + } + + super.appendExtraCtorCode(builder, ctx, builderTag); + } + + @Override + protected void appendExtraToBuilderBuilderFunctions(StringBuilder builder, + BodyContext ctx, + String decl) { + if (ctx.doingConcreteType()) { + String decl1 = decl.replace("{args}", Config.class.getName() + " cfg"); + javaDocToBuilder(builder, ctx, "cfg"); + builder.append("\t").append(decl1).append(" {\n"); + builder.append("\t\tBuilder b = builder();\n" + + "\t\tb.acceptConfig(cfg, true);\n" + + "\t\treturn b;\n" + + "\t}\n"); + } + + super.appendExtraToBuilderBuilderFunctions(builder, ctx, decl); + } + + @Override + protected void appendExtraBuilderMethods(StringBuilder builder, + BodyContext ctx) { + if (ctx.doingConcreteType()) { + super.appendExtraBuilderMethods(builder, ctx); + return; + } + + if (!ctx.hasParent()) { + builder.append("\t\t@Override\n"); + builder.append("\t\tpublic void acceptConfig" + + "(Config cfg, ConfigResolver resolver, ConfigBeanBuilderValidator validator) {\n"); + builder.append("\t\t\t").append(ResolutionCtx.class.getName()) + .append(" ctx = createResolutionContext(__configBeanType(), cfg, resolver, validator);\n"); + builder.append("\t\t\t__config(ctx.config());\n"); + builder.append("\t\t\t__acceptAndResolve(ctx);\n"); + builder.append("\t\t\tsuper.finishedResolution(ctx);\n"); + builder.append("\t\t}\n\n"); + } + + if (!ctx.doingConcreteType()) { + if (ctx.hasParent()) { + builder.append("\t\t@Override\n"); + } else { + javaDocAcceptResolveConfigCtx(builder, ctx, "ctx"); + } + builder.append("\t\tprotected void __acceptAndResolve(").append(ResolutionCtx.class.getName()).append(" ctx) {\n"); + if (ctx.hasParent()) { + builder.append("\t\t\tsuper.__acceptAndResolve(ctx);\n"); + } + + int i = 0; + for (String attrName : ctx.allAttributeNames()) { + TypedElementName method = ctx.allTypeInfos().get(i); + String configKey = toConfigKey(attrName, method, ctx.builderAnnotation()); + + // resolver.of(config, "port", int.class).ifPresent(this::port); + String ofClause = "of"; + TypeName outerType = method.typeName(); + String outerTypeName = outerType.declaredName(); + TypeName type = outerType; + String typeName = type.declaredName(); + TypeName mapKeyType = null; + TypeName mapKeyComponentType = null; + boolean isMap = typeName.equals(Map.class.getName()); + boolean isCollection = ( + typeName.equals(Collection.class.getName()) + || typeName.equals(Set.class.getName()) + || typeName.equals(List.class.getName())); + if (isCollection) { + ofClause = "ofCollection"; + type = type.typeArguments().get(0); + typeName = type.declaredName(); + } else if (isMap) { + ofClause = "ofMap"; + mapKeyType = type.typeArguments().get(0); + if (!mapKeyType.typeArguments().isEmpty()) { + mapKeyComponentType = mapKeyType.typeArguments().get(0); + } + type = type.typeArguments().get(1); + typeName = type.declaredName(); + } else if (Optional.class.getName().equals(typeName)) { + type = type.typeArguments().get(0); + typeName = type.declaredName(); + } + + builder.append("\t\t\tctx.resolver().").append(ofClause); + builder.append("(ctx, __metaAttributes(), ").append(DefaultConfigResolverRequest.class.getPackage().getName()); + builder.append(".DefaultConfigResolver"); + if (isMap) { + builder.append("Map"); + } + builder.append("Request.builder()\n\t\t\t\t\t"); + builder.append(".configKey(\"").append(configKey); + builder.append("\").attributeName(\"").append(attrName).append("\")"); + builder.append(".valueType(").append(outerTypeName).append(".class)"); + if (type != outerType) { + builder.append(".valueComponentType(").append(typeName).append(".class)"); + } + if (isMap) { + builder.append(".keyType(").append(Objects.requireNonNull(mapKeyType)).append(".class)"); + if (Objects.nonNull(mapKeyComponentType)) { + builder.append(".keyComponentType(").append(mapKeyComponentType.name()).append(".class)"); + } + } + builder.append(".build())\n\t\t\t\t\t.ifPresent((val) -> this.").append(method.elementName()).append("(("); + builder.append(outerTypeName).append(") val));\n"); + i++; + } + + builder.append("\t\t}\n\n"); + } + + builder.append("\t\t@Override\n"); + builder.append("\t\tpublic Class __configBeanType() {\n" + + "\t\t\treturn ") + .append(ctx.typeInfo().typeName().name()).append(".class;\n\t\t}\n\n"); + + super.appendExtraBuilderMethods(builder, ctx); + } + + @Override + protected boolean overridesVisitAttributes(BodyContext ctx) { + return true; + } + + private void appendConfigBeanInfoAttributes(StringBuilder builder, + TypeInfo typeInfo, + AnnotationAndValue configBeanAnno) { + String configKey = configBeanAnno.value("key").orElse(null); + configKey = normalizeConfiguredOptionKey(configKey, typeInfo.typeName().className(), null); + + builder.append("\t\t\t\t\t\t.key(\"") + .append(Objects.requireNonNull(configKey)).append("\")\n"); + builder.append("\t\t\t\t\t\t.repeatable(") + .append(configBeanAnno.value("repeatable").orElseThrow()).append(")\n"); + builder.append("\t\t\t\t\t\t.drivesActivation(") + .append(configBeanAnno.value("drivesActivation").orElseThrow()).append(")\n"); + builder.append("\t\t\t\t\t\t.atLeastOne(") + .append(configBeanAnno.value("atLeastOne").orElseThrow()).append(")\n"); + } + + private void javaDocMetaAttributesGetter(StringBuilder builder) { + builder.append("\t/**\n" + + "\t * Returns the {@code ConfigBean} type.\n" + + "\t *\n" + + "\t * @return the config bean type\n" + + "\t */\n"); + } + + private void javaDocToBuilder(StringBuilder builder, + BodyContext ctx, + String argTag) { + builder.append("\t/**\n" + + "\t * Creates a builder for this type, initialized with the Config value passed.\n" + + "\t *\n"); + builder.append("\t * @param ").append(argTag).append(" the config to copy and initialize from\n"); + builder.append("\t * @return a fluent builder for {@link ").append(ctx.typeInfo().typeName()); + builder.append("}\n\t */\n"); + } + + private void javaDocAcceptResolveConfigCtx(StringBuilder builder, + BodyContext ctx, + String argTag) { + builder.append("\t\t/**\n" + + "\t\t * Accept the config, resolves it, optionally validates.\n" + + "\t\t *\n"); + builder.append("\t\t * @param ").append(argTag).append(" the config resolution context\n"); + builder.append("\t\t */\n"); + } + + private String toConfigKey(String attrName, + TypedElementName method, + AnnotationAndValue ignoredBuilderAnnotation) { + String configKey = null; + Optional configuredOptions = DefaultAnnotationAndValue + .findFirst(ConfiguredOption.class.getName(), method.annotations()); + if (configuredOptions.isPresent()) { + configKey = configuredOptions.get().value("key").orElse(null); + } + if (Objects.isNull(configKey) || configKey.isBlank()) { + configKey = ConfigBeanInfo.toConfigKey(attrName); + } + return configKey; + } + + private void assertNoAnnotation(String annoTypeName, + TypeInfo typeInfo) { + Optional anno = DefaultAnnotationAndValue + .findFirst(annoTypeName, typeInfo.annotations()); + if (anno.isPresent()) { + throw new IllegalStateException(annoTypeName + " cannot be used in conjunction with " + + ConfigBean.class.getName() + + " on " + typeInfo.typeName()); + } + + for (TypedElementName elem : typeInfo.elementInfo()) { + anno = DefaultAnnotationAndValue.findFirst(annoTypeName, elem.annotations()); + if (anno.isEmpty()) { + anno = DefaultAnnotationAndValue.findFirst(annoTypeName, elem.elementTypeAnnotations()); + } + if (anno.isPresent()) { + throw new IllegalStateException(annoTypeName + " cannot be used in conjunction with " + + ConfigBean.class.getName() + + " on " + typeInfo.typeName() + "." + elem + "()"); + } + } + + if (typeInfo.superTypeInfo().isPresent()) { + assertNoAnnotation(annoTypeName, typeInfo.superTypeInfo().get()); + } + } + +} diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java new file mode 100644 index 00000000000..e6609e38653 --- /dev/null +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Pico ConfigBean Processor extensions. + */ +package io.helidon.pico.builder.config.processor.tools; diff --git a/pico/builder-config/processor/src/main/java/module-info.java b/pico/builder-config/processor/src/main/java/module-info.java new file mode 100644 index 00000000000..ad05aef5373 --- /dev/null +++ b/pico/builder-config/processor/src/main/java/module-info.java @@ -0,0 +1,38 @@ +/* + * 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 Pico ConfigBean Builder Processor (Tools) module. + */ +module io.helidon.pico.builder.config.processor { + requires jakarta.inject; + requires io.helidon.common; + requires io.helidon.common.config; + requires io.helidon.config.metadata; + requires io.helidon.pico.builder.config; + requires io.helidon.pico.builder.processor; + requires io.helidon.pico.builder.processor.spi; + requires io.helidon.pico.builder.processor.tools; + requires io.helidon.pico.types; + requires io.helidon.pico; + + exports io.helidon.pico.builder.config.processor.tools; + + uses io.helidon.pico.builder.processor.spi.BuilderCreator; + + provides io.helidon.pico.builder.processor.spi.BuilderCreator + with io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; +} diff --git a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java new file mode 100644 index 00000000000..5d921d05f3c --- /dev/null +++ b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java @@ -0,0 +1,37 @@ +/* + * 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.pico.builder.config.tools.tests; + +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; +import io.helidon.pico.builder.processor.spi.BuilderCreator; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + +class ConfigBeanBuilderCreatorTest { + + @Test + void supportedAnnotationTypes() { + BuilderCreator creator = new ConfigBeanBuilderCreator(); + assertEquals(1, creator.supportedAnnotationTypes().size()); + assertSame(ConfigBean.class, creator.supportedAnnotationTypes().iterator().next()); + } + +} diff --git a/pico/builder-config/tests/configbean/README.md b/pico/builder-config/tests/configbean/README.md new file mode 100644 index 00000000000..a9c613736c9 --- /dev/null +++ b/pico/builder-config/tests/configbean/README.md @@ -0,0 +1,2 @@ +# pico-builder-config-test-config +Tests for ConfigBean-generated builder types. diff --git a/pico/builder-config/tests/configbean/pom.xml b/pico/builder-config/tests/configbean/pom.xml new file mode 100644 index 00000000000..76648bbe2dc --- /dev/null +++ b/pico/builder-config/tests/configbean/pom.xml @@ -0,0 +1,142 @@ + + + + + + io.helidon.pico.builder.config.tests + helidon-pico-builder-config-tests-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + helidon-pico-builder-config-tests-test-config + Helidon Pico ConfigBean Tests + + + true + true + true + true + true + true + true + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config + + + io.helidon.config + helidon-config + test + + + jakarta.inject + jakarta.inject-api + provided + + + jakarta.annotation + jakarta.annotation-api + provided + + + io.helidon.pico.builder.config + helidon-pico-builder-config-processor + provided + + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -XprintProcessorInfo + -XprintRounds + -verbose + + true + + + io.helidon.pico.builder.config + helidon-pico-builder-config-processor + ${helidon.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + + diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java new file mode 100644 index 00000000000..65fb259f034 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes; + +/** + * Indicates whether the server requires authentication of tbe client by the certificate. + */ +public enum FakeClientAuth { + + /** + * Authentication is required. + */ + REQUIRE(FakeNettyClientAuth.REQUIRE), + + /** + * Authentication is optional. + */ + OPTIONAL(FakeNettyClientAuth.OPTIONAL), + + /** + * Authentication is not required. + */ + NONE(FakeNettyClientAuth.NONE); + + private final FakeNettyClientAuth clientAuth; + + FakeClientAuth(FakeNettyClientAuth clientAuth) { + this.clientAuth = clientAuth; + } + + FakeNettyClientAuth nettyClientAuth(){ + return clientAuth; + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java new file mode 100644 index 00000000000..05c0330801b --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java @@ -0,0 +1,232 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ComponentTracing. + * + * A component is a single "layer" of the application that can trace. + * Component examples: + *

    + *
  • web-server: webServer adds the root tracing span + two additional spans (content-read and content-write)
  • + *
  • security: security adds the overall request security span, a span for authentication ("security:atn"), a span for + * authorization "security:atz", and a span for response processing ("security:response")
  • + *
  • jax-rs: JAX-RS integration adds spans for overall resource invocation
  • + *
+ */ +@ConfigBean +public interface FakeComponentTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled component - all subsequent calls return disabled spans and logs. +// */ +// public static final ComponentTracingConfig DISABLED = ComponentTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * Enabled component - all subsequent calls return enabled spans and logs. +// */ +// public static final ComponentTracingConfig ENABLED = ComponentTracingConfig.builder("enabled").build(); + +// /** +// * A new named component. +// * +// * @param name name of the component +// */ +// protected ComponentTracingConfig(String name) { +// super(name); +// } +// + +// /** +// * Merge configuration of two traced components. This enabled hierarchical configuration +// * with common, default configuration in one traced component and override in another. +// * +// * @param older the older configuration with "defaults" +// * @param newer the newer configuration to override defaults in older +// * @return merged component +// */ +// static ComponentTracingConfig merge(ComponentTracingConfig older, ComponentTracingConfig newer) { +// return new ComponentTracingConfig(newer.name()) { +// @Override +// public Optional getSpan(String spanName) { +// if (!enabled()) { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// +// Optional newSpan = newer.getSpan(spanName); +// Optional oldSpan = older.getSpan(spanName); +// +// // both configured +// if (newSpan.isPresent() && oldSpan.isPresent()) { +// return Optional.of(SpanTracingConfig.merge(oldSpan.get(), newSpan.get())); +// } +// +// // only newer +// if (newSpan.isPresent()) { +// return newSpan; +// } +// +// return oldSpan; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of the span in this component +// * @return configuration of that span if present +// */ +// protected abstract Optional getSpan(String spanName); +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @return configuration of the span, or enabled configuration if not configured +// * @see #span(String, boolean) +// */ +// public SpanTracingConfig span(String spanName) { +// return span(spanName, true); +// } + + @Singular("span") // Builder::addSpan(String span, FakeSpanLogTracingConfigBean val), Impl::getSpan(String span), etc. + Map spanLogMap(); + +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @param enabledByDefault whether the result is enabled if a configuration is not present +// * @return configuration of the span, or a span configuration enabled or disabled depending on {@code enabledByDefault} if +// * not configured +// */ +// public SpanTracingConfig span(String spanName, boolean enabledByDefault) { +// if (enabled()) { +// return getSpan(spanName).orElseGet(() -> enabledByDefault ? SpanTracingConfig.ENABLED : SpanTracingConfig.DISABLED); +// } +// +// return SpanTracingConfig.DISABLED; +// } +// +// /** +// * Fluent API builder for traced component. +// * +// * @param name the name of the component +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced component configuration from {@link Config}. +// * +// * @param name name of the component +// * @param config config for a new component +// * @return a new traced component configuration +// */ +// public static ComponentTracingConfig create(String name, Config config) { +// return builder(name) +// .config(config) +// .build(); +// } +// +// /** +// * Fluent API builder for {@link ComponentTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map tracedSpans = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// private final String name; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public ComponentTracingConfig build() { +// // immutability +// final Optional finalEnabled = enabled; +// final Map finalSpans = new HashMap<>(tracedSpans); +// return new ComponentTracingConfig(name) { +// @Override +// public Optional getSpan(String spanName) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpans.get(spanName)); +// } else { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of a traced component +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("spans").asNodeList().ifPresent(spanConfigList -> { +// spanConfigList.forEach(spanConfig -> { +// // span name is mandatory +// addSpan(SpanTracingConfig.create(spanConfig.get("name").asString().get(), spanConfig)); +// }); +// }); +// return this; +// } +// +// /** +// * Add a new traced span configuration. +// * +// * @param span configuration of a traced span +// * @return updated builder instance +// */ +// public Builder addSpan(SpanTracingConfig span) { +// this.tracedSpans.put(span.name(), span); +// return this; +// } +// +// /** +// * Configure whether this component is enabled or disabled. +// * +// * @param enabled if disabled, all spans and logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java new file mode 100644 index 00000000000..fefe6cfd5cb --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java @@ -0,0 +1,842 @@ +/* + * 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.pico.builder.config.fakes; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * aka KeyConfig. + * + */ +@Builder +public interface FakeKeyConfig { + + // /*private static final*/ String DEFAULT_PRIVATE_KEY_ALIAS = "1"; +// /*private static final*/ char[] EMPTY_CHARS = new char[0]; + +// private static final Logger LOGGER = Logger.getLogger(FakeKeyConfigBean.class.getName()); +// +// private final PrivateKey privateKey; +// private final PublicKey publicKey; +// private final X509Certificate publicCert; +// private final List certChain = new LinkedList<>(); +// private final List certificates = new LinkedList<>(); +// +// private FakeKeyConfigBean(PrivateKey privateKey, +// PublicKey publicKey, +// X509Certificate publicCert, +// Collection certChain, +// Collection certificates) { +// +// this.privateKey = privateKey; +// this.publicKey = publicKey; +// this.publicCert = publicCert; +// this.certChain.addAll(certChain); +// this.certificates.addAll(certificates); +// } +// +// /** +// * Load key config from config. +// * +// * @param config config instance located at keys configuration (expects "keystore-path" child) +// * @return KeyConfig loaded from config +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// public static FakeKeyConfigBean create(Config config) throws PkiException { +// try { +// return fullBuilder().config(config).build(); +// } catch (ResourceException e) { +// throw new PkiException("Failed to load from config", e); +// } +// } +// +// /** +// * Creates a new builder to configure instance. +// * +// * @return builder instance +// */ +// public static Builder fullBuilder() { +// return new Builder(); +// } +// +// /** +// * Build this instance from PEM files (usually a pair of private key and certificate chain). +// * Call {@link PemBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for PEM files +// */ +// public static PemBuilder pemBuilder() { +// return new PemBuilder(); +// } +// +// /** +// * Build this instance from a java keystore (such as PKCS12 keystore). +// * Call {@link KeystoreBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for Keystore +// */ +// public static KeystoreBuilder keystoreBuilder() { +// return new KeystoreBuilder(); +// } +// + /** + * The public key of this config if configured. + * + * @return the public key of this config or empty if not configured + */ + /*public*/ Optional publicKey(); +// { +// return Optional.ofNullable(publicKey); +// } + + /** + * The private key of this config if configured. + * + * @return the private key of this config or empty if not configured + */ + /*public*/ Optional privateKey(); +// { +// return Optional.ofNullable(privateKey); +// } + + /** + * The public X.509 Certificate if configured. + * + * @return the public certificate of this config or empty if not configured + */ + /*public*/ Optional publicCert(); +// { +// return Optional.ofNullable(publicCert); +// } + + /** + * The X.509 Certificate Chain. + * + * @return the certificate chain or empty list if not configured + */ + /*public*/ List certChain(); +// { +// return Collections.unmodifiableList(certChain); +// } + + /** + * The X.509 Certificates. + * + * @return the certificates configured or empty list if none configured + */ + /*public*/ List certs(); +// { +// return Collections.unmodifiableList(certificates); +// } + + + /** + * @see FakeKeystoreConfig + */ +// public DefaultFakeConfigBean.Builder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + + +// /** +// * Fluent API builder for {@link FakeKeyConfigBean}. +// * Call {@link #build()} to create an instance. +// * +// * The keys may be loaded from multiple possible sources. +// * +// * @see FakeKeyConfigBean#keystoreBuilder() +// * @see FakeKeyConfigBean#pemBuilder() +// * @see FakeKeyConfigBean#fullBuilder() +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private PrivateKey explicitPrivateKey; +// private PublicKey explicitPublicKey; +// private X509Certificate explicitPublicCert; +// private final List explicitCertChain = new LinkedList<>(); +// private final List explicitCertificates = new LinkedList<>(); +// +// /** +// * Build a new instance of the configuration based on this builder. +// * +// * @return instance from this builder +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// @Override +// public FakeKeyConfigBean build() throws PkiException { +// PrivateKey privateKey = this.explicitPrivateKey; +// PublicKey publicKey = this.explicitPublicKey; +// X509Certificate publicCert = this.explicitPublicCert; +// List certChain = new LinkedList<>(explicitCertChain); +// List certificates = new LinkedList<>(explicitCertificates); +// +// // fix public key if cert is provided +// if (null == publicKey && null != publicCert) { +// publicKey = publicCert.getPublicKey(); +// } +// +// return new FakeKeyConfigBean(privateKey, publicKey, publicCert, certChain, certificates); +// } +// +// /** +// * Configure a private key instance (rather then keystore and alias). +// * +// * @param privateKey private key instance +// * @return updated builder instance +// */ +// public Builder privateKey(PrivateKey privateKey) { +// this.explicitPrivateKey = privateKey; +// return this; +// } +// +// /** +// * Configure a public key instance (rather then keystore and certificate alias). +// * +// * @param publicKey private key instance +// * @return updated builder instance +// */ +// public Builder publicKey(PublicKey publicKey) { +// this.explicitPublicKey = publicKey; +// return this; +// } +// +// /** +// * Configure an X.509 certificate instance for public key certificate. +// * +// * @param certificate certificate instance +// * @return updated builder instance +// */ +// public Builder publicKeyCert(X509Certificate certificate) { +// this.explicitPublicCert = certificate; +// return this; +// } +// +// /** +// * Add an X.509 certificate instance to the end of certification chain. +// * +// * @param certificate certificate to add to certification path +// * @return updated builder instance +// */ +// public Builder addCertChain(X509Certificate certificate) { +// this.explicitCertChain.add(certificate); +// return this; +// } +// +// /** +// * Add a certificate to the list of certificates, used e.g. in a trust store. +// * +// * @param certificate X.509 certificate to trust +// * @return updated builder instance +// */ +// public Builder addCert(X509Certificate certificate) { +// this.explicitCertificates.add(certificate); +// return this; +// } +// +// /** +// * Update this builder with information from a pem builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#pemBuilder()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "pem") +// public Builder updateWith(PemBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Update this builder with information from a keystore builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#keystoreBuilder()} ()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "keystore") +// public Builder updateWith(KeystoreBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Updated this builder instance from configuration. +// * Keys configured will override existing fields in this builder, others will be left intact. +// * If certification path is already defined, configuration based cert-path will be added. +// * +// * @param config configuration to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// updateWith(pemBuilder().config(config)); +// updateWith(keystoreBuilder().config(config)); +// +// return this; +// } +// } +// +// /** +// * Builder for resources from a java keystore (PKCS12, JKS etc.). Obtain an instance through {@link +// * FakeKeyConfigBean#keystoreBuilder()}. +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class KeystoreBuilder implements io.helidon.common.Builder { +// private static final String DEFAULT_KEYSTORE_TYPE = "PKCS12"; +// +// private String keystoreType = DEFAULT_KEYSTORE_TYPE; +// private char[] keystorePassphrase = EMPTY_CHARS; +// private char[] keyPassphrase = null; +// private String keyAlias; +// private String certAlias; +// private String certChainAlias; +// private boolean addAllCertificates; +// private final List certificateAliases = new LinkedList<>(); +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); +// +// private KeystoreBuilder() { +// } +// +// /** +// * If you want to build a trust store, call this method to add all +// * certificates present in the keystore to certificate list. +// * +// * @return updated builder instance +// */ +// @ConfiguredOption(type = Boolean.class, value = "false") +// public KeystoreBuilder trustStore() { +// return trustStore(true); +// } +// +// private KeystoreBuilder trustStore(boolean isTrustStore) { +// this.addAllCertificates = isTrustStore; +// return this; +// } +// +// /** +// * Add an alias to list of aliases used to generate a trusted set of certificates. +// * +// * @param alias alias of a certificate +// * @return updated builder instance +// */ +// public KeystoreBuilder addCertAlias(String alias) { +// certificateAliases.add(alias); +// return this; +// } +// +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// +// /** +// * Set type of keystore. +// * Defaults to "PKCS12", expected are other keystore types supported by java then can store keys under aliases. +// * +// * @param keystoreType keystore type to load the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "type", value = "PKCS12") +// public KeystoreBuilder keystoreType(String keystoreType) { +// this.keystoreType = keystoreType; +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassphrase keystore pass-phrase +// * @return updated builder instance +// */ +// public KeystoreBuilder keystorePassphrase(char[] keystorePassphrase) { +// this.keystorePassphrase = Arrays.copyOf(keystorePassphrase, keystorePassphrase.length); +// +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassword keystore password to use, calls {@link #keystorePassphrase(char[])} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "passphrase") +// public KeystoreBuilder keystorePassphrase(String keystorePassword) { +// return keystorePassphrase(keystorePassword.toCharArray()); +// } +// +// /** +// * Alias of the private key in the keystore. +// * +// * @param keyAlias alias of the key in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.alias", value = "1") +// public KeystoreBuilder keyAlias(String keyAlias) { +// this.keyAlias = keyAlias; +// return this; +// } +// +// /** +// * Alias of X.509 certificate of public key. +// * Used to load both the certificate and public key. +// * +// * @param alias alias under which the certificate is stored in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert.alias") +// public KeystoreBuilder certAlias(String alias) { +// this.certAlias = alias; +// return this; +// } +// +// /** +// * Alias of an X.509 chain. +// * +// * @param alias alias of certificate chain in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.alias") +// public KeystoreBuilder certChainAlias(String alias) { +// this.certChainAlias = alias; +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// public KeystoreBuilder keyPassphrase(char[] privateKeyPassphrase) { +// this.keyPassphrase = Arrays.copyOf(privateKeyPassphrase, privateKeyPassphrase.length); +// +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public KeystoreBuilder keyPassphrase(String privateKeyPassphrase) { +// return keyPassphrase(privateKeyPassphrase.toCharArray()); +// } +// +// /** +// * Create an instance of {@link FakeKeyConfigBean} based on this builder. +// * +// * @return new key config based on a keystore +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Create a builder for {@link FakeKeyConfigBean} from this keystore builder. This allows you to enhance the config +// * with additional (explicit) fields. +// * +// * @return builder of {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// + +// private Builder updateBuilder(Builder builder) { +// if (keystoreStream.isSet()) { +// if (null == keyPassphrase) { +// keyPassphrase = keystorePassphrase; +// } +// KeyStore keyStore; +// +// try { +// keyStore = PkiUtil.loadKeystore(keystoreType, +// keystoreStream.stream(), +// keystorePassphrase, +// keystoreStream.message()); +// } finally { +// keystoreStream.closeStream(); +// } +// +// // attempt to read private key +// boolean guessing = false; +// if (null == keyAlias) { +// keyAlias = DEFAULT_PRIVATE_KEY_ALIAS; +// guessing = true; +// } +// try { +// builder.privateKey(PkiUtil.loadPrivateKey(keyStore, keyAlias, keyPassphrase)); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to read private key from default alias", e); +// } else { +// throw e; +// } +// } +// +// List certChain = null; +// if (null == certChainAlias) { +// guessing = true; +// // by default, cert chain uses the same alias as private key +// certChainAlias = keyAlias; +// } else { +// guessing = false; +// } +// +// if (null != certChainAlias) { +// try { +// certChain = PkiUtil.loadCertChain(keyStore, certChainAlias); +// certChain.forEach(builder::addCertChain); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to certificate chain from alias \"" + certChainAlias + "\"", e); +// } else { +// throw e; +// } +// } +// } +// +// if (null == certAlias) { +// // no explicit public key certificate, just load it from cert chain if present +// if (null != certChain && !certChain.isEmpty()) { +// builder.publicKeyCert(certChain.get(0)); +// } +// } else { +// builder.publicKeyCert(PkiUtil.loadCertificate(keyStore, certAlias)); +// } +// +// if (addAllCertificates) { +// PkiUtil.loadCertificates(keyStore).forEach(builder::addCert); +// } else { +// certificateAliases.forEach(it -> builder.addCert(PkiUtil.loadCertificate(keyStore, it))); +// } +// } +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } +// } +// + +// /** +// * Builder for PEM files - accepts private key and certificate chain. Obtain an instance through {@link +// * FakeKeyConfigBean#pemBuilder()}. +// * +// * If you have "standard" linux/unix private key, you must run " +// * {@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa.p8}" on it to work with this builder for password protected +// * file; or "{@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa_nocrypt.p8 -nocrypt}" for unprotected file. +// * +// * The only supported format is PKCS#8. If you have a different format, you must to transform it to PKCS8 PEM format (to +// * use this builder), or to PKCS#12 keystore format (and use {@link KeystoreBuilder}). +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class PemBuilder implements io.helidon.common.Builder { +// private final StreamHolder privateKeyStream = new StreamHolder("privateKey"); +// private final StreamHolder publicKeyStream = new StreamHolder("publicKey"); +// private final StreamHolder certChainStream = new StreamHolder("certChain"); +// private final StreamHolder certificateStream = new StreamHolder("certificate"); +// private char[] pemKeyPassphrase; +// +// private PemBuilder() { +// } +// +// /** +// * Read a private key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.resource") +// public PemBuilder key(Resource resource) { +// privateKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Read a public key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder publicKey(Resource resource) { +// publicKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// public PemBuilder keyPassphrase(char[] passphrase) { +// this.pemKeyPassphrase = Arrays.copyOf(passphrase, passphrase.length); +// +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public PemBuilder keyPassphrase(String passphrase) { +// return keyPassphrase(passphrase.toCharArray()); +// } +// +// /** +// * Load certificate chain from PEM resource. +// * +// * @param resource resource (e.g. classpath, file path, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.resource") +// public PemBuilder certChain(Resource resource) { +// certChainStream.stream(resource); +// return this; +// } +// +// /** +// * Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder certificates(Resource resource) { +// certificateStream.stream(resource); +// return this; +// } +// +// /** +// * Build {@link FakeKeyConfigBean} based on information from PEM files only. +// * +// * @return new instance configured from this builder +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Get a builder filled from this builder to add additional information (such as public key from certificate etc.). +// * +// * @return builder for {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// +// private Builder updateBuilder(Builder builder) { +// if (privateKeyStream.isSet()) { +// builder.privateKey(PemReader.readPrivateKey(privateKeyStream.stream(), pemKeyPassphrase)); +// } +// if (publicKeyStream.isSet()) { +// builder.publicKey(PemReader.readPublicKey(publicKeyStream.stream())); +// } +// +// if (certChainStream.isSet()) { +// List chain = PemReader.readCertificates(certChainStream.stream()); +// chain.forEach(builder::addCertChain); +// if (!chain.isEmpty()) { +// builder.publicKeyCert(chain.get(0)); +// } +// } +// +// if (certificateStream.isSet()) { +// PemReader.readCertificates(certificateStream.stream()).forEach(builder::addCert); +// } +// +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * Expected keys: +// *
    +// *
  • pem-key-path - path to PEM private key file (PKCS#8 format)
  • +// *
  • pem-key-resource-path - path to resource on classpath
  • +// *
  • pem-key-passphrase - passphrase of private key if encrypted
  • +// *
  • pem-cert-chain-path - path to certificate chain PEM file
  • +// *
  • pem-cert-chain-resource-path - path to resource on classpath
  • +// *
+// * +// * @param config configuration to update builder from +// * @return updated builder instance +// */ +// public PemBuilder config(Config config) { +// Config pemConfig = config.get("pem"); +// pemConfig.get("key.resource").as(Resource::create).ifPresent(this::key); +// pemConfig.get("key.passphrase").asString().map(String::toCharArray).ifPresent(this::keyPassphrase); +// pemConfig.get("cert-chain.resource").as(Resource::create).ifPresent(this::certChain); +// pemConfig.get("certificates.resource").as(Resource::create).ifPresent(this::certificates); +// return this; +// } +// } +// +// private static final class StreamHolder { +// private final String baseMessage; +// private InputStream inputStream; +// private String message; +// +// private StreamHolder(String message) { +// this.baseMessage = message; +// this.message = message; +// } +// +// private boolean isSet() { +// return inputStream != null; +// } +// +// private void stream(Resource resource) { +// closeStream(); +// Objects.requireNonNull(resource, "Resource for \"" + message + "\" must not be null"); +// +// this.inputStream = resource.stream(); +// this.message = message + ":" + resource.sourceType() + ":" + resource.location(); +// } +// +// private InputStream stream() { +// return inputStream; +// } +// +// private String message() { +// return message; +// } +// +// private void closeStream() { +// if (null != inputStream) { +// try { +// inputStream.close(); +// } catch (IOException e) { +// LOGGER.log(Level.WARNING, "Failed to close input stream: " + message, e); +// } +// } +// message = baseMessage; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java new file mode 100644 index 00000000000..bd02e890646 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java @@ -0,0 +1,134 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka KeyConfig.Keystore.Builder + * + * This is a ConfigBean since it marries up to the backing config. + */ +@ConfigBean +public interface FakeKeystoreConfig { + + String DEFAULT_KEYSTORE_TYPE = "PKCS12"; + +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); + +// default FakeKeystoreConfigBean trustStore() { +// return trustStore(true); +// } + + @ConfiguredOption(key = "trust-store") + boolean trustStore(); + +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// default DefaultFakeKeystoreConfigBean.Builder keystore(Resource keystore) { +// +// } + + @ConfiguredOption(key = "type", value = DEFAULT_KEYSTORE_TYPE) + String keystoreType(); + + @ConfiguredOption(key = "passphrase") + char[] keystorePassphrase(); + + @ConfiguredOption(key = "key.alias", value = "1") + String keyAlias(); + + @ConfiguredOption(key = "key.passphrase") + char[] keyPassphrase(); + + @ConfiguredOption(key = "cert.alias") + @Singular("certAlias") + List certAliases(); + + @ConfiguredOption(key = "cert-chain.alias") + String certChainAlias(); + + +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java new file mode 100644 index 00000000000..26809c9d12a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes; + +public enum FakeNettyClientAuth { + NONE, + OPTIONAL, + REQUIRE; + + private FakeNettyClientAuth() { + } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java new file mode 100644 index 00000000000..1f1a094d05a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java @@ -0,0 +1,179 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka PathTracing. + * + * Traced system configuration for web server for a specific path. + */ +@ConfigBean +public interface FakePathTracingConfig { +// /** +// * Create a new traced path configuration from {@link io.helidon.config.Config}. +// * @param config config of a path +// * @return traced path configuration +// */ +// static FakePathTracingConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * Create a new builder to configure traced path configuration. +// * +// * @return a new builder instance +// */ +// static Builder builder() { +// return new Builder(); +// } + + /** + * Path this configuration should configure. + * + * @return path on the web server + */ + String path(); + + /** + * Method(s) this configuration should be valid for. This can be used to restrict the configuration + * only to specific HTTP methods (such as {@code GET} or {@code POST}). + * + * @return list of methods, if empty, this configuration is valid for any method + */ + @Singular("method") // Builder::addMethod(String method); + List methods(); + +// /** +// * Associated configuration of tracing valid for the configured path and (possibly) methods. +// * +// * @return traced system configuration +// */ + @ConfiguredOption(required = true) + FakeTracingConfig tracedConfig(); + +// Optional tracedConfig(); + + +// /** +// * Fluent API builder for {@link FakePathTracingConfigBean}. +// */ +// final class Builder implements io.helidon.common.Builder { +// private final List methods = new LinkedList<>(); +// private String path; +// private TracingConfig tracedConfig; +// +// private Builder() { +// } +// +// @Override +// public FakePathTracingConfigBean build() { +// // immutable +// final String finalPath = path; +// final List finalMethods = new LinkedList<>(methods); +// final TracingConfig finalTracingConfig = tracedConfig; +// +// return new FakePathTracingConfigBean() { +// @Override +// public String path() { +// return finalPath; +// } +// +// @Override +// public List methods() { +// return finalMethods; +// } +// +// @Override +// public TracingConfig tracedConfig() { +// return finalTracingConfig; +// } +// +// @Override +// public String toString() { +// return path + "(" + finalMethods + "): " + finalTracingConfig; +// } +// }; +// } +// +// /** +// * Update this builder from provided {@link io.helidon.config.Config}. +// * +// * @param config config to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// path(config.get("path").asString().get()); +// List methods = config.get("methods").asList(String.class).orElse(null); +// if (null != methods) { +// methods(methods); +// } +// tracingConfig(TracingConfig.create(config)); +// +// return this; +// } +// +// /** +// * Path to register the traced configuration on. +// * +// * @param path path as understood by {@link io.helidon.webserver.Routing.Builder} of web server +// * @return updated builder instance +// */ +// public Builder path(String path) { +// this.path = path; +// return this; +// } +// +// /** +// * HTTP methods to restrict registration of this configuration on web server. +// * @param methods list of methods to use, empty means all methods +// * @return updated builder instance +// */ +// public Builder methods(List methods) { +// this.methods.clear(); +// this.methods.addAll(methods); +// return this; +// } +// +// /** +// * Add a new HTTP method to restrict this configuration for. +// * +// * @param method method to add to the list of supported methods +// * @return updated builder instance +// */ +// public Builder addMethod(String method) { +// this.methods.add(method); +// return this; +// } +// +// /** +// * Configuration of a traced system to use on this path and possibly method(s). +// * +// * @param tracedConfig configuration of components, spans and span logs +// * @return updated builder instance +// */ +// public Builder tracingConfig(TracingConfig tracedConfig) { +// this.tracedConfig = tracedConfig; +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java new file mode 100644 index 00000000000..df7086be20e --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java @@ -0,0 +1,694 @@ +/* + * 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.pico.builder.config.fakes; + +/* + * 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. + */ + +/** + * aka Routing. + */ +public interface FakeRoutingConfig extends FakeServerLifecycle { + +// void route(BareRequest bareRequest, BareResponse bareResponse); +// +// /** +// * Creates new instance of {@link Builder routing builder}. +// * +// * @return a new instance +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * An API to define HTTP request routing rules. +// * +// * @see Builder +// */ +// interface Rules { +// /** +// * Configuration of tracing for this routing. +// * The configuration may control whether to log specific components, +// * spans and span logs, either globally, or for a specific path and method combinations. +// * +// * @param webTracingConfig WebServer tracing configuration +// * @return Updated routing configuration +// */ +// Rules register(WebTracingConfig webTracingConfig); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return Updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(Supplier... serviceBuilders); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(String pathPattern, Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return an updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(String pathPattern, Supplier... serviceBuilders); +// +// /** +// * Routes all GET requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(Handler... requestHandlers); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(String pathPattern, Handler... requestHandlers); +// +// /** +// * Add a route. This allows also protocol version specific routing. +// * +// * @param route route to add +// * @return updated rules +// */ +// Rules route(HttpRoute route); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all PUT requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for a registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all POST requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all RFC 5789 PATCH requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all DELETE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all OPTIONS requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all HEAD requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all TRACE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes requests any specified method to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Registers callback on created new {@link WebServer} instance with this routing. +// * +// * @param webServerConsumer a WebServer creation callback +// * @return updated routing configuration +// */ +// Rules onNewWebServer(Consumer webServerConsumer); +// } +// +// /** +// * A {@link Routing} builder. +// */ +// class Builder implements Rules, io.helidon.common.Builder { +// +// private final RouteListRoutingRules delegate = new RouteListRoutingRules(); +// private final List> errorHandlerRecords = new ArrayList<>(); +// private boolean tracingRegistered; +// +// /** +// * Creates new instance. +// */ +// private Builder() { +// } +// +// // --------------- ROUTING API +// +// @Override +// public Builder register(WebTracingConfig webTracingConfig) { +// this.tracingRegistered = true; +// delegate.register(webTracingConfig); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(Supplier... serviceBuilders) { +// delegate.register(serviceBuilders); +// return this; +// } +// +// @Override +// public Builder register(Service... services) { +// delegate.register(services); +// return this; +// } +// +// @Override +// public Builder register(String pathPattern, Service... services) { +// delegate.register(pathPattern, services); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(String pathPattern, Supplier... serviceBuilders) { +// delegate.register(pathPattern, serviceBuilders); +// return this; +// } +// +// @Override +// public Builder get(Handler... requestHandlers) { +// delegate.get(requestHandlers); +// return this; +// } +// +// @Override +// public Builder get(String pathPattern, Handler... requestHandlers) { +// delegate.get(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder route(HttpRoute route) { +// delegate.register(route); +// return this; +// } +// +// @Override +// public Builder get(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.get(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(Handler... requestHandlers) { +// delegate.put(requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(String pathPattern, Handler... requestHandlers) { +// delegate.put(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.put(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(Handler... requestHandlers) { +// delegate.post(requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(String pathPattern, Handler... requestHandlers) { +// delegate.post(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.post(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(Handler... requestHandlers) { +// delegate.patch(requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(String pathPattern, Handler... requestHandlers) { +// delegate.patch(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.patch(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(Handler... requestHandlers) { +// delegate.delete(requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(String pathPattern, Handler... requestHandlers) { +// delegate.delete(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.delete(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(Handler... requestHandlers) { +// delegate.options(requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(String pathPattern, Handler... requestHandlers) { +// delegate.options(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.options(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(Handler... requestHandlers) { +// delegate.head(requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(String pathPattern, Handler... requestHandlers) { +// delegate.head(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.head(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(Handler... requestHandlers) { +// delegate.trace(requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(String pathPattern, Handler... requestHandlers) { +// delegate.trace(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.trace(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(Handler... requestHandlers) { +// delegate.any(requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(String pathPattern, Handler... requestHandlers) { +// delegate.any(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.any(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, Handler... requestHandlers) { +// delegate.anyOf(methods, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, String pathPattern, Handler... requestHandlers) { +// delegate.anyOf(methods, pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, +// PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.anyOf(methods, pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder onNewWebServer(Consumer webServerConsumer) { +// delegate.onNewWebServer(webServerConsumer); +// return this; +// } +// // --------------- ERROR API +// +// /** +// * Registers an error handler that handles the given type of exceptions. +// * +// * @param exceptionClass the type of exception to handle by this handler +// * @param errorHandler the error handler +// * @param an error handler type +// * @return an updated builder +// */ +// public Builder error(Class exceptionClass, ErrorHandler errorHandler) { +// if (errorHandler == null) { +// return this; +// } +// errorHandlerRecords.add(RequestRouting.ErrorHandlerRecord.of(exceptionClass, errorHandler)); +// +// return this; +// } +// +// // --------------- BUILD API +// +// /** +// * Builds a new routing instance. +// * +// * @return a new instance +// */ +// public Routing build() { +// if (!tracingRegistered) { +// register(WebTracingConfig.create()); +// } +// RouteListRoutingRules.Aggregation aggregate = delegate.aggregate(); +// return new RequestRouting(aggregate.routeList(), errorHandlerRecords, aggregate.newWebServerCallbacks()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java new file mode 100644 index 00000000000..b1099652728 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java @@ -0,0 +1,763 @@ +/* + * 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.pico.builder.config.fakes; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ServerConfiguration. + */ +@ConfigBean +public interface FakeServerConfig extends FakeSocketConfig { + + /** + * Returns the count of threads in the pool used to process HTTP requests. + *

+ * Default value is {@link Runtime#availableProcessors()}. + * + * @return a workers count + */ + int workersCount(); + + /** + * Returns a server port to listen on with the default server socket. If port is + * {@code 0} then any available ephemeral port will be used. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return the server port of the default server socket + */ + @Override + int port(); + +// /** +// * Returns local address where the server listens on with the default server socket. +// * If {@code null} then listens an all local addresses. +// *

+// * Additional named server socket configuration is accessible through +// * the {@link #socket(String)} and {@link #sockets()} methods. +// * +// * @return an address to bind with the default server socket; {@code null} for all local addresses +// */ +// @Override +// InetAddress bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the default server + * socket. + *

+ * Default value is {@link FakeSocketConfig#DEFAULT_BACKLOG_SIZE}. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a maximum length of the queue of incoming connections + */ + @Override + int backlog(); + + /** + * Returns a default server socket timeout in milliseconds or {@code 0} for an infinite timeout. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a default server socket timeout in milliseconds or {@code 0} + */ + @Override + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * default server socket. + *

+ * If {@code 0} then use implementation default. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a buffer size in bytes of the default server socket or {@code 0} + */ + @Override + int receiveBufferSize(); + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code null} if there is no such + * named server socket + * @deprecated since 2.0.0, please use {@link #namedSocket(String)} instead + */ + @Deprecated + default FakeSocketConfig socket(String name) { + return namedSocket(name).orElse(null); + } + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code empty} if there is no such + * named server socket configured + */ + default Optional namedSocket(String name) { + return Optional.ofNullable(sockets().get(name)); + } + + /** + * A map of all the configured server sockets; that is the default server socket + * which is identified by the key {@link io.helidon.pico.config.fake.helidon.WebServer#DEFAULT_SOCKET_NAME} and also all the additional + * named server socket configurations. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @return a map of all the configured server sockets, never null + */ + @Singular("socket") + Map sockets(); + + /** + * The maximum amount of time that the server will wait to shut + * down regardless of the value of any additionally requested + * quiet period. + * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(10L)}.

+ * + * @return the {@link java.time.Duration} to use + */ +// TODO: @DefaultValue (Duration translation) + @ConfiguredOption(key = "whatever") + default Duration maxShutdownTimeout() { + return Duration.ofSeconds(10L); + } + + /** + * The quiet period during which the webserver will wait for new + * incoming connections after it has been told to shut down. + * + *

The webserver will wait no longer than the duration returned + * by the {@link #maxShutdownTimeout()} method.

+ * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(0L)}, indicating + * that there will be no quiet period.

+ * + * @return the {@link java.time.Duration} to use + */ + default Duration shutdownQuietPeriod() { + return Duration.ofSeconds(0L); + } + +// /** +// * Returns a Tracer. +// * +// * @return a tracer to use - never {@code null} +// */ +// Tracer tracer(); + +// /** +// * The top level {@link io.helidon.common.context.Context} to be used by this webserver. +// * @return a context instance with registered application scoped instances +// */ +// Context context(); +// +// /** +// * Returns an optional {@link Transport}. +// * +// * @return an optional {@link Transport} +// */ +// default Optional transport() { +// return Optional.ofNullable(null); +// } + + /** + * Whether to print details of HelidonFeatures. + * + * @return whether to print details + */ + boolean printFeatureDetails(); + +// /** +// * Creates new instance with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new instance +// */ +// static FakeServerConfigBean create(Config config) { +// return builder(config).build(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder}. +// * +// * @return a new builder instance +// * +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()} instead +// */ +// @Deprecated +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder} with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new builder instance +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()}, then +// * {@link WebServer.Builder#config(io.helidon.config.Config)}, or +// * {@link io.helidon.webserver.WebServer#create(Routing, io.helidon.config.Config)} +// */ +// @Deprecated +// static Builder builder(Config config) { +// return new Builder().config(config); +// } +// +// /** +// * A {@link FakeServerConfigBean} builder. +// * +// * @deprecated since 2.0.0 - use {@link io.helidon.webserver.WebServer.Builder} instead +// */ +// @Deprecated +// final class Builder implements FakeSocketConfigBean.SocketConfigurationBuilder, +// io.helidon.common.Builder { +// +// private static final AtomicInteger WEBSERVER_COUNTER = new AtomicInteger(1); +// private final Map socketBuilders = new HashMap<>(); +// private final Map socketsConfigs = new HashMap<>(); +// private int workers; +// private Tracer tracer; +// private Duration maxShutdownTimeout; +// private Duration shutdownQuietPeriod; +// private Optional transport; +// private Context context; +// private boolean printFeatureDetails; +// +// private Builder() { +// transport = Optional.ofNullable(null); +// maxShutdownTimeout = Duration.ofSeconds(10L); +// shutdownQuietPeriod = Duration.ofSeconds(0L); +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContext ssl context +// * @return an updated builder +// */ +// public Builder ssl(SSLContext sslContext) { +// defaultSocketBuilder().ssl(sslContext); +// return this; +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContextBuilder ssl context builder; will be built as a first step of this method execution +// * @return an updated builder +// */ +// public Builder ssl(Supplier sslContextBuilder) { +// defaultSocketBuilder().ssl(sslContextBuilder); +// return this; +// } +// +// /** +// * Sets server port. If port is {@code 0} or less then any available ephemeral port will be used. +// *

+// * Configuration key: {@code port} +// * +// * @param port the server port +// * @return an updated builder +// */ +// public Builder port(int port) { +// defaultSocketBuilder().port(port); +// return this; +// } +// +// /** +// * Sets a local address for server to bind. If {@code null} then listens an all local addresses. +// *

+// * Configuration key: {@code bind-address} +// * +// * @param bindAddress the address to bind the server or {@code null} for all local addresses +// * @return an updated builder +// */ +// public Builder bindAddress(InetAddress bindAddress) { +// defaultSocketBuilder().bindAddress(bindAddress); +// return this; +// } +// +// /** +// * Sets a maximum length of the queue of incoming connections. Default value is {@code 1024}. +// *

+// * Configuration key: {@code backlog} +// * +// * @param size the maximum length of the queue of incoming connections +// * @return an updated builder +// */ +// public Builder backlog(int size) { +// defaultSocketBuilder().backlog(size); +// return this; +// } +// +// /** +// * Sets a socket timeout in milliseconds or {@code 0} for infinite timeout. +// *

+// * Configuration key: {@code timeout} +// * +// * @param milliseconds a socket timeout in milliseconds or {@code 0} +// * @return an updated builder +// */ +// public Builder timeout(int milliseconds) { +// defaultSocketBuilder().timeoutMillis(milliseconds); +// return this; +// } +// +// /** +// * Propose value of the TCP receive window that is advertised to the remote peer. +// * If {@code 0} then implementation default is used. +// *

+// * Configuration key: {@code receive-buffer} +// * +// * @param bytes a buffer size in bytes or {@code 0} +// * @return an updated builder +// */ +// public Builder receiveBufferSize(int bytes) { +// defaultSocketBuilder().receiveBufferSize(bytes); +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// defaultSocketBuilder().maxHeaderSize(size); +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// defaultSocketBuilder().maxInitialLineLength(length); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param port the port to bind; if {@code 0} or less, any available ephemeral port will be used +// * @param bindAddress the address to bind; if {@code null}, all local addresses will be bound +// * @return an updated builder +// * +// * @deprecated since 2.0.0, please use {@link #addSocket(String, FakeSocketConfigBean)} instead +// */ +// @Deprecated +// public Builder addSocket(String name, int port, InetAddress bindAddress) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// return addSocket(name, FakeSocketConfigBean.builder() +// .port(port) +// .bindAddress(bindAddress)); +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketsConfigs.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration builder +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean.Builder socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketBuilders.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration builder. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as +// * a first step of this method execution +// * @return an updated builder +// */ +// public Builder addSocket(String name, Supplier socketConfigurationBuilder) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// +// return addSocket(name, socketConfigurationBuilder != null ? socketConfigurationBuilder.get() : null); +// } +// +// /** +// * Sets a count of threads in pool used to process HTTP requests. +// * Default value is {@code CPU_COUNT * 2}. +// *

+// * Configuration key: {@code workers} +// * +// * @param workers a workers count +// * @return an updated builder +// */ +// public Builder workersCount(int workers) { +// this.workers = workers; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracer a tracer to set +// * @return an updated builder +// */ +// public Builder tracer(Tracer tracer) { +// this.tracer = tracer; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution +// * @return updated builder +// */ +// public Builder tracer(Supplier tracerBuilder) { +// return tracer(tracerBuilder.get()); +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(String... protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(List protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configure maximum client payload size. +// * @param size maximum payload size +// * @return an updated builder +// */ +// @Override +// public Builder maxPayloadSize(long size) { +// defaultSocketBuilder().maxPayloadSize(size); +// return this; +// } +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @Override +// public Builder maxUpgradeContentLength(int size) { +// defaultSocketBuilder().maxUpgradeContentLength(size); +// return this; +// } +// +// /** +// * Configure the maximum amount of time that the server will wait to shut +// * down regardless of the value of any additionally requested +// * quiet period. +// * @param maxShutdownTimeout the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder maxShutdownTimeout(Duration maxShutdownTimeout) { +// this.maxShutdownTimeout = +// Objects.requireNonNull(maxShutdownTimeout, "Parameter 'maxShutdownTimeout' must not be null!"); +// return this; +// } +// +// /** +// * Configure the quiet period during which the webserver will wait for new +// * incoming connections after it has been told to shut down. +// * @param shutdownQuietPeriod the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder shutdownQuietPeriod(Duration shutdownQuietPeriod) { +// this.shutdownQuietPeriod = +// Objects.requireNonNull(shutdownQuietPeriod, "Parameter 'shutdownQuietPeriod' must not be null!"); +// return this; +// } +// +// /** +// * Configure transport. +// * @param transport a {@link Transport} +// * @return an updated builder +// */ +// public Builder transport(Transport transport) { +// this.transport = Optional.of(transport); +// return this; +// } +// +// /** +// * Set to {@code true} to print detailed feature information on startup. +// * +// * @param print whether to print details or not +// * @return updated builder instance +// * @see io.helidon.common.HelidonFeatures +// */ +// public Builder printFeatureDetails(boolean print) { +// this.printFeatureDetails = print; +// return this; +// } +// +// /** +// * Configure the application scoped context to be used as a parent for webserver request contexts. +// * @param context top level context +// * @return an updated builder +// */ +// public Builder context(Context context) { +// this.context = context; +// +// return this; +// } +// +// private InetAddress string2InetAddress(String address) { +// try { +// return InetAddress.getByName(address); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * Sets configuration values included in provided {@link Config} parameter. +// *

+// * It can be used for configuration externalisation. +// *

+// * All parameters sets before this method call can be seen as defaults and all parameters sets after can be seen +// * as forced. +// * +// * @param config the configuration to use +// * @return an updated builder +// */ +// public Builder config(Config config) { +// if (config == null) { +// return this; +// } +// +// defaultSocketBuilder().config(config); +// +// config.get("host").asString().ifPresent(defaultSocketBuilder()::host); +// +// DeprecatedConfig.get(config, "worker-count", "workers") +// .asInt() +// .ifPresent(this::workersCount); +// +// config.get("features.print-details").asBoolean().ifPresent(this::printFeatureDetails); +// +// // shutdown timeouts +// config.get("max-shutdown-timeout-seconds").asLong().ifPresent(it -> maxShutdownTimeout(Duration.ofSeconds(it))); +// config.get("shutdown-quiet-period-seconds").asLong().ifPresent(it -> shutdownQuietPeriod(Duration.ofSeconds(it))); +// +// // sockets +// Config socketsConfig = config.get("sockets"); +// if (socketsConfig.exists()) { +// List socketConfigs = socketsConfig.asNodeList().orElse(List.of()); +// for (Config socketConfig : socketConfigs) { +// // the whole section checking the socket name can be removed +// // when we remove deprecated methods with socket name on server builder +// String socketName; +// +// String nodeName = socketConfig.name(); +// Optional maybeSocketName = socketConfig.get("name").asString().asOptional(); +// +// socketName = maybeSocketName.orElse(nodeName); +// +// // log warning for deprecated config +// try { +// Integer.parseInt(nodeName); +// if (socketName.equals(nodeName) && maybeSocketName.isEmpty()) { +// throw new ConfigException("Cannot find \"name\" key for socket configuration " + socketConfig.key()); +// } +// } catch (NumberFormatException e) { +// // this is old approach +// Logger.getLogger(SocketConfigurationBuilder.class.getName()) +// .warning("Socket configuration at " + socketConfig.key() + " is deprecated. Please use an array " +// + "with \"name\" key to define the socket name."); +// } +// +// FakeSocketConfigBean.Builder socket = FakeSocketConfigBean.builder() +// .name(socketName) +// .config(socketConfig); +// +// socketBuilders.put(socket.name(), socket); +// } +// } +// +// return this; +// } +// +// /** +// * Builds a new configuration instance. +// * +// * @return a new instance +// */ +// @Override +// public FakeServerConfigBean build() { +// if (null == context) { +// // I do not expect "unlimited" number of webservers +// // in case somebody spins a huge number up, the counter will cycle to negative numbers once +// // Integer.MAX_VALUE is reached. +// context = Context.builder() +// .id("web-" + WEBSERVER_COUNTER.getAndIncrement()) +// .build(); +// } +// +// Optional maybeTracer = context.get(Tracer.class); +// +// if (null == this.tracer) { +// this.tracer = maybeTracer.orElseGet(Tracer::global); +// } +// +// if (maybeTracer.isEmpty()) { +// context.register(this.tracer); +// } +// +// if (workers <= 0) { +// workers = Runtime.getRuntime().availableProcessors(); +// } +// +// return new ServerBasicConfig(this); +// } +// +// FakeSocketConfigBean.Builder defaultSocketBuilder() { +// return socketBuilder(WebServer.DEFAULT_SOCKET_NAME); +// } +// +// FakeSocketConfigBean.Builder socketBuilder(String socketName) { +// return socketBuilders.computeIfAbsent(socketName, k -> FakeSocketConfigBean.builder().name(socketName)); +// } +// +// Map sockets() { +// Set builtSocketConfigsKeys = socketsConfigs.keySet(); +// Map result = +// new HashMap<>(this.socketBuilders.size() + this.socketsConfigs.size()); +// for (Map.Entry e : this.socketBuilders.entrySet()) { +// String key = e.getKey(); +// if (builtSocketConfigsKeys.contains(key)) { +// throw new IllegalStateException("Both mutable and immutable socket configuration provided for named socket " +// + key); +// } +// result.put(key, e.getValue().build()); +// } +// +// result.putAll(this.socketsConfigs); +// return result; +// } +// +// int workers() { +// return workers; +// } +// +// Tracer tracer() { +// return tracer; +// } +// +// Duration maxShutdownTimeout() { +// return maxShutdownTimeout; +// } +// +// Duration shutdownQuietPeriod() { +// return shutdownQuietPeriod; +// } +// +// Optional transport() { +// return transport; +// } +// +// Context context() { +// return context; +// } +// +// boolean printFeatureDetails() { +// return printFeatureDetails; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// defaultSocketBuilder().timeout(amount, unit); +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// defaultSocketBuilder().tls(webServerTls); +// return this; +// } +// +// @Override +// public Builder enableCompression(boolean value) { +// defaultSocketBuilder().enableCompression(value); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java new file mode 100644 index 00000000000..e08e34b6093 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java @@ -0,0 +1,37 @@ +/* + * 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.pico.builder.config.fakes; + +/** + * aka ServerLifecycle. + * Basic server lifecycle operations. + */ +public interface FakeServerLifecycle { + +// /** +// * Before server start. +// */ +// default void beforeStart() { +// } +// +// /** +// * After server stop. +// */ +// default void afterStop() { +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java new file mode 100644 index 00000000000..9b7dcb3ba93 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java @@ -0,0 +1,847 @@ +/* + * 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.pico.builder.config.fakes; + +/* + * 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 java.util.Optional; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ServerConfiguration. + * + * The SocketConfiguration configures a port to listen on and its associated server socket parameters. + */ +@ConfigBean +public interface FakeSocketConfig { + + /** + * The default backlog size to configure the server sockets with if no other value + * is provided. + */ + int DEFAULT_BACKLOG_SIZE = 1024; + + /** + * Name of this socket. + * Default to WebServer#DEFAULT_SOCKET_NAME for the main and + * default server socket. All other sockets must be named. + * + * @return name of this socket + */ +// default String name() { +// return WebServer.DEFAULT_SOCKET_NAME; +// } + @ConfiguredOption(WebServer.DEFAULT_SOCKET_NAME) + String name(); + + /** + * Returns a server port to listen on with the server socket. If port is + * {@code 0} then any available ephemeral port will be used. + * + * @return the server port of the server socket + */ + int port(); + +// /** +// * Returns local address where the server listens on with the server socket. +// * If {@code null} then listens an all local addresses. +// * +// * @return an address to bind with the server socket; {@code null} for all local addresses +// */ +// InetAddress bindAddress(); + @ConfiguredOption(key = "bind-address") + String bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the server + * socket. + *

+ * Default value is {@link #DEFAULT_BACKLOG_SIZE}. + * + * @return a maximum length of the queue of incoming connections + */ + @ConfiguredOption("1024") + int backlog(); + + /** + * Returns a server socket timeout in milliseconds or {@code 0} for an infinite timeout. + * + * @return a server socket timeout in milliseconds or {@code 0} + */ + @ConfiguredOption(key = "timeout-millis") + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * server socket. + *

+ * If {@code 0} then use implementation default. + * + * @return a buffer size in bytes of the server socket or {@code 0} + */ + int receiveBufferSize(); + + /** + * Return a {@link FakeWebServerTlsConfig} containing server TLS configuration. When empty {@link java.util.Optional} is returned + * no TLS should be configured. + * + * @return web server tls configuration + */ + Optional tls(); + + /** + * Returns a {@link javax.net.ssl.SSLContext} to use with the server socket. If not {@code null} then + * the server enforces an SSL communication. + * + * @deprecated use {@code tls().sslContext()} instead. This method will be removed at 3.0.0 version. + * @return a SSL context to use + */ + @Deprecated(since = "2.3.1", forRemoval = true) + SSLContext ssl(); + + /** + * Returns the SSL protocols to enable, or {@code null} to enable the default + * protocols. + * @deprecated use {@code tls().enabledTlsProtocols()} instead. This method will be removed at 3.0.0 version. + * @return the SSL protocols to enable + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set enabledSslProtocols(); + + /** + * Return the allowed cipher suite of the TLS. If empty set is returned, the default cipher suite is used. + * + * @deprecated use {@code tls().cipherSuite()} instead. This method will be removed at 3.0.0 version. + * @return the allowed cipher suite + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set allowedCipherSuite(); + + /** + * Whether to require client authentication or not. + * + * @deprecated use {@code tls().clientAuth()} instead. This method will be removed at 3.0.0 version. + * @return client authentication + */ + @Deprecated(since = "2.3.1", forRemoval = true) + FakeNettyClientAuth clientAuth(); + + /** + * Whether this socket is enabled (and will be opened on server startup), or disabled + * (and ignored on server startup). + * + * @return {@code true} for enabled socket, {@code false} for socket that should not be opened + */ +// default boolean enabled() { +// return true; +// } + @ConfiguredOption("true") + boolean enabled(); + + /** + * Maximal size of all headers combined. + * + * @return size in bytes + */ + @ConfiguredOption(key = "max-header-size", value = "8192") + int maxHeaderSize(); + + /** + * Maximal length of the initial HTTP line. + * + * @return length + */ + @ConfiguredOption("4096") + int maxInitialLineLength(); + + /** + * Maximal size of a single chunk of received data. + * + * @return chunk size + */ + int maxChunkSize(); + + /** + * Whether to validate HTTP header names. + * When set to {@code true}, we make sure the header name is a valid string + * + * @return {@code true} if headers should be validated + */ + boolean validateHeaders(); + + /** + * Whether to allow negotiation for a gzip/deflate content encoding. Supporting + * HTTP compression may interfere with application that use streaming and other + * similar features. Thus, it defaults to {@code false}. + * + * @return compression flag + */ +// default boolean enableCompression() { +// return false; +// } + boolean enableCompression(); + + /** + * Maximum size allowed for an HTTP payload in a client request. A negative + * value indicates that there is no maximum set. + * + * @return maximum payload size + */ +// default long maxPayloadSize() { +// return -1L; +// } + @ConfiguredOption("-1") + long maxPayloadSize(); + + /** + * Initial size of the buffer used to parse HTTP line and headers. + * + * @return initial size of the buffer + */ + int initialBufferSize(); + + /** + * Maximum length of the content of an upgrade request. + * + * @return maximum length of the content of an upgrade request + */ +// default int maxUpgradeContentLength() { +// return 64 * 1024; +// } + @ConfiguredOption("65536") + int maxUpgradeContentLength(); + +// /** +// * Creates a builder of {@link FakeSocketConfigBean} class. +// * +// * @return a builder +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create a default named configuration. +// * +// * @param name name of the socket +// * @return a new socket configuration with defaults +// */ +// static FakeSocketConfigBean create(String name) { +// return builder() +// .name(name) +// .build(); +// } +// +// /** +// * Socket configuration builder API, used by {@link io.helidon.webserver.SocketConfiguration.Builder} +// * to configure additional sockets, and by {@link io.helidon.webserver.WebServer.Builder} to +// * configure the default socket. +// * +// * @param type of the subclass of this class to provide correct fluent API +// */ +// @Configured +// interface SocketConfigurationBuilder> { +// /** +// * Configures a server port to listen on with the server socket. If port is +// * {@code 0} then any available ephemeral port will be used. +// * +// * @param port the server port of the server socket +// * @return this builder +// */ +// @ConfiguredOption("0") +// B port(int port); +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param address an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// * @throws io.helidon.config.ConfigException in case the address provided is not a valid host address +// */ +// @ConfiguredOption(deprecated = true) +// default B bindAddress(String address) { +// try { +// return bindAddress(InetAddress.getByName(address)); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * A helper method that just calls {@link #bindAddress(String)}. +// * +// * @param address host to listen on +// * @return this builder +// */ +// @ConfiguredOption +// default B host(String address) { +// return bindAddress(address); +// } +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param bindAddress an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// */ +// B bindAddress(InetAddress bindAddress); +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// @ConfiguredOption("1024") +// B backlog(int backlog); +// +// /** +// * Configures a server socket timeout. +// * +// * @param amount an amount of time to configure the timeout, use {@code 0} for infinite timeout +// * @param unit time unit to use with the configured amount +// * @return this builder +// */ +// @ConfiguredOption(key = "timeout-millis", type = Long.class, value = "0", +// description = "Socket timeout in milliseconds") +// B timeout(long amount, TimeUnit unit); +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @ConfiguredOption +// B receiveBufferSize(int receiveBufferSize); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * If this method is called, any other method except for {@link #tls(java.util.function.Supplier)}¨ +// * and repeated invocation of this method would be ignored. +// *

+// * If this method is called again, the previous configuration would be ignored. +// * +// * @param webServerTls ssl configuration to use with this socket +// * @return this builder +// */ +// @ConfiguredOption +// B tls(FakeWebServerTlsConfigBean webServerTls); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * +// * @param tlsConfig supplier ssl configuration to use with this socket +// * @return this builder +// */ +// default B tls(Supplier tlsConfig) { +// return tls(tlsConfig.get()); +// } +// +// /** +// * Maximal number of bytes of all header values combined. When a bigger value is received, a +// * {@link io.helidon.common.http.Http.Status#BAD_REQUEST_400} +// * is returned. +// *

+// * Default is {@code 8192} +// * +// * @param size maximal number of bytes of combined header values +// * @return this builder +// */ +// @ConfiguredOption("8192") +// B maxHeaderSize(int size); +// +// /** +// * Maximal number of characters in the initial HTTP line. +// *

+// * Default is {@code 4096} +// * +// * @param length maximal number of characters +// * @return this builder +// */ +// @ConfiguredOption("4096") +// B maxInitialLineLength(int length); +// +// /** +// * Enable negotiation for gzip/deflate content encodings. Clients can +// * request compression using the "Accept-Encoding" header. +// *

+// * Default is {@code false} +// * +// * @param value compression flag +// * @return this builder +// */ +// @ConfiguredOption("false") +// B enableCompression(boolean value); +// +// /** +// * Set a maximum payload size for a client request. Can prevent DoS +// * attacks. +// * +// * @param size maximum payload size +// * @return this builder +// */ +// @ConfiguredOption +// B maxPayloadSize(long size); +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @ConfiguredOption("65536") +// B maxUpgradeContentLength(int size); +// +// /** +// * Update this socket configuration from a {@link io.helidon.config.Config}. +// * +// * @param config configuration on the node of a socket +// * @return updated builder instance +// */ +// @SuppressWarnings("unchecked") +// default B config(Config config) { +// config.get("port").asInt().ifPresent(this::port); +// config.get("bind-address").asString().ifPresent(this::host); +// config.get("backlog").asInt().ifPresent(this::backlog); +// config.get("max-header-size").asInt().ifPresent(this::maxHeaderSize); +// config.get("max-initial-line-length").asInt().ifPresent(this::maxInitialLineLength); +// config.get("max-payload-size").asInt().ifPresent(this::maxPayloadSize); +// +// DeprecatedConfig.get(config, "timeout-millis", "timeout") +// .asInt() +// .ifPresent(it -> this.timeout(it, TimeUnit.MILLISECONDS)); +// DeprecatedConfig.get(config, "receive-buffer-size", "receive-buffer") +// .asInt() +// .ifPresent(this::receiveBufferSize); +// +// Optional> enabledProtocols = DeprecatedConfig.get(config, "ssl.protocols", "ssl-protocols") +// .asList(String.class) +// .asOptional(); +// +// // tls +// Config sslConfig = DeprecatedConfig.get(config, "tls", "ssl"); +// if (sslConfig.exists()) { +// try { +// FakeWebServerTlsConfigBean.Builder builder = FakeWebServerTlsConfigBean.builder(); +// enabledProtocols.ifPresent(builder::enabledProtocols); +// builder.config(sslConfig); +// +// this.tls(builder.build()); +// } catch (IllegalStateException e) { +// throw new ConfigException("Cannot load SSL configuration.", e); +// } +// } +// +// // compression +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// return (B) this; +// } +// } +// +// /** +// * The {@link io.helidon.webserver.SocketConfiguration} builder class. +// */ +// @Configured +// final class Builder implements SocketConfigurationBuilder, io.helidon.common.Builder { +// /** +// * @deprecated remove once WebServer.Builder.addSocket(name, socket) methods are removed +// */ +// @Deprecated +// static final String UNCONFIGURED_NAME = "io.helidon.webserver.SocketConfiguration.UNCONFIGURED"; +// private final FakeWebServerTlsConfigBean.Builder tlsConfigBuilder = FakeWebServerTlsConfigBean.builder(); +// +// private int port = 0; +// private InetAddress bindAddress = null; +// private int backlog = DEFAULT_BACKLOG_SIZE; +// private int timeoutMillis = 0; +// private int receiveBufferSize = 0; +// private FakeWebServerTlsConfigBean webServerTls; +// // this is for backward compatibility, should be initialized to null once the +// // methods with `name` are removed from server builder (for adding sockets) +// private String name = UNCONFIGURED_NAME; +// private boolean enabled = true; +// // these values are as defined in Netty implementation +// private int maxHeaderSize = 8192; +// private int maxInitialLineLength = 4096; +// private int maxChunkSize = 8192; +// private boolean validateHeaders = true; +// private int initialBufferSize = 128; +// private boolean enableCompression = false; +// private long maxPayloadSize = -1; +// private int maxUpgradeContentLength = 64 * 1024; +// +// private Builder() { +// } +// +// @Override +// public FakeSocketConfigBean build() { +// if (null == webServerTls) { +// webServerTls = tlsConfigBuilder.build(); +// } +// +// if (null == name) { +// throw new ConfigException("Socket name must be configured for each socket"); +// } +// +// return new ServerBasicConfig.SocketConfig(this); +// } +// +// @Override +// public Builder port(int port) { +// this.port = port; +// return this; +// } +// +// @Override +// public Builder bindAddress(InetAddress bindAddress) { +// this.bindAddress = bindAddress; +// return this; +// } +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// public Builder backlog(int backlog) { +// this.backlog = backlog; +// return this; +// } +// +// /** +// * Configures a server socket timeout in milliseconds or {@code 0} for an infinite timeout. +// * +// * @param timeoutMillis a server socket timeout in milliseconds or {@code 0} +// * @return this builder +// * +// * @deprecated since 2.0.0 please use {@link #timeout(long, java.util.concurrent.TimeUnit)} instead +// */ +// @Deprecated +// public Builder timeoutMillis(int timeoutMillis) { +// this.timeoutMillis = timeoutMillis; +// return this; +// } +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @Override +// public Builder receiveBufferSize(int receiveBufferSize) { +// this.receiveBufferSize = receiveBufferSize; +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContext a SSL context to use +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link #tls(FakeWebServerTlsConfigBean)} instead +// */ +// @Deprecated +// public Builder ssl(SSLContext sslContext) { +// if (null != sslContext) { +// this.tlsConfigBuilder.sslContext(sslContext); +// } +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContextBuilder a SSL context builder to use; will be built as a first step of this +// * method execution +// * @return this builder +// * @deprecated since 2.0.0, please use {@link #tls(Supplier)} instead +// */ +// @Deprecated +// public Builder ssl(Supplier sslContextBuilder) { +// return ssl(sslContextBuilder != null ? sslContextBuilder.get() : null); +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link FakeWebServerTlsConfigBean.Builder#enabledProtocols(String...)} +// * instead +// */ +// @Deprecated +// public Builder enabledSSlProtocols(String... protocols) { +// if (null == protocols) { +// enabledSSlProtocols(List.of()); +// } else { +// enabledSSlProtocols(Arrays.asList(protocols)); +// } +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return this builder +// */ +// @Deprecated +// public Builder enabledSSlProtocols(List protocols) { +// if (null == protocols) { +// this.tlsConfigBuilder.enabledProtocols(List.of()); +// } else { +// this.tlsConfigBuilder.enabledProtocols(protocols); +// } +// return this; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// long timeout = unit.toMillis(amount); +// if (timeout > Integer.MAX_VALUE) { +// this.timeoutMillis = 0; +// } else { +// this.timeoutMillis = (int) timeout; +// } +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// this.webServerTls = webServerTls; +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// this.maxHeaderSize = size; +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// this.maxInitialLineLength = length; +// return this; +// } +// +// @Override +// public Builder maxPayloadSize(long size) { +// this.maxPayloadSize = size; +// return this; +// } +// +// @Override +// public Builder maxUpgradeContentLength(int size) { +// this.maxUpgradeContentLength = size; +// return this; +// } +// +// /** +// * Configure a socket name, to bind named routings to. +// * +// * @param name name of the socket +// * @return updated builder instance +// */ +// @ConfiguredOption(required = true) +// public Builder name(String name) { +// this.name = name; +// return this; +// } +// +// /** +// * Set this socket builder to enabled or disabled. +// * +// * @param enabled when set to {@code false}, the socket is not going to be opened by the server +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// return this; +// } +// +// /** +// * Configure maximal size of a chunk to be read from incoming requests. +// * Defaults to {@code 8192}. +// * +// * @param size maximal chunk size +// * @return updated builder instance +// */ +// public Builder maxChunkSize(int size) { +// this.maxChunkSize = size; +// return this; +// } +// +// /** +// * Configure whether to validate header names. +// * Defaults to {@code true} to make sure header names are valid strings. +// * +// * @param validate set to {@code false} to ignore header validation +// * @return updated builder instance +// */ +// public Builder validateHeaders(boolean validate) { +// this.validateHeaders = validate; +// return this; +// } +// +// /** +// * Configure initial size of the buffer used to parse HTTP line and headers. +// * Defaults to {@code 128}. +// * +// * @param size initial buffer size +// * @return updated builder instance +// */ +// public Builder initialBufferSize(int size) { +// this.initialBufferSize = size; +// return this; +// } +// +// /** +// * Configure whether to enable content negotiation for compression. +// * +// * @param value compression flag +// * @return updated builder instance +// */ +// public Builder enableCompression(boolean value) { +// this.enableCompression = value; +// return this; +// } +// +// @Override +// public Builder config(Config config) { +// SocketConfigurationBuilder.super.config(config); +// +// config.get("name").asString().ifPresent(this::name); +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("max-chunk-size").asInt().ifPresent(this::maxChunkSize); +// config.get("validate-headers").asBoolean().ifPresent(this::validateHeaders); +// config.get("initial-buffer-size").asInt().ifPresent(this::initialBufferSize); +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// +// return this; +// } +// +// int port() { +// return port; +// } +// +// Optional bindAddress() { +// return Optional.ofNullable(bindAddress); +// } +// +// int backlog() { +// return backlog; +// } +// +// int timeoutMillis() { +// return timeoutMillis; +// } +// +// int receiveBufferSize() { +// return receiveBufferSize; +// } +// +// FakeWebServerTlsConfigBean tlsConfig() { +// return webServerTls; +// } +// +// String name() { +// return name; +// } +// +// boolean enabled() { +// return enabled; +// } +// +// int maxHeaderSize() { +// return maxHeaderSize; +// } +// +// int maxInitialLineLength() { +// return maxInitialLineLength; +// } +// +// int maxChunkSize() { +// return maxChunkSize; +// } +// +// boolean validateHeaders() { +// return validateHeaders; +// } +// +// int initialBufferSize() { +// return initialBufferSize; +// } +// +// boolean enableCompression() { +// return enableCompression; +// } +// +// long maxPayloadSize() { +// return maxPayloadSize; +// } +// +// int maxUpgradeContentLength() { +// return maxUpgradeContentLength; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java new file mode 100644 index 00000000000..398d44c44c6 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java @@ -0,0 +1,129 @@ +/* + * 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.pico.builder.config.fakes; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanLogTracingConfig. + * Configuration of a single log event in a traced span. + */ +@ConfigBean +public interface FakeSpanLogTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean DISABLED = FakeSpanLogTracingConfigBean.builder("disabled").enabled(false).build(); +// /** +// * Enabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean ENABLED = FakeSpanLogTracingConfigBean.builder("enabled").build(); +// +// /** +// * A new span log. +// * @param name name of the span log +// */ +// protected FakeSpanLogTracingConfigBean(String name) { +// super(name); +// } +// + +// /** +// * Merge two traced span log configurations. +// * +// * @param older original configuration with default values +// * @param newer new configuration to override the older +// * @return a new traced span log mergint the older and newer +// */ +// static FakeSpanLogTracingConfigBean merge(FakeSpanLogTracingConfigBean older, FakeSpanLogTracingConfigBean newer) { +// return new FakeSpanLogTracingConfigBean(newer.name()) { +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Fluent API builder to create a new traced span log configuration. +// * +// * @param name name of the span log +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced span log configuration from {@link io.helidon.config.Config}. +// * +// * @param name name of the span log +// * @param config config for a traced span log +// * @return a new traced span log configuration +// */ +// public static FakeSpanLogTracingConfigBean create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link FakeSpanLogTracingConfigBean}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final String name; +// private Optional enabled = Optional.empty(); +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public FakeSpanLogTracingConfigBean build() { +// final Optional finalEnabled = enabled; +// return new FakeSpanLogTracingConfigBean(name) { +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Configure whether this traced span log is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config config of a traced span log +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java new file mode 100644 index 00000000000..db45e5b1746 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java @@ -0,0 +1,258 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Map; +import java.util.Optional; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanTracingConfig. + * + * Configuration of a single traced span. + */ +@ConfigBean +public interface FakeSpanTracingConfig extends FakeTraceableConfig { + +// /** +// * A traced span that is disabled and all logs on it are disabled as well. +// */ +// public static final SpanTracingConfig DISABLED = SpanTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * A traced span that is inabled and all logs on it are enabled as well. +// */ +// public static final SpanTracingConfig ENABLED = SpanTracingConfig.builder("enabled").build(); + +// /** +// * A new traceable span. +// * +// * @param name name of this span +// */ +// protected SpanTracingConfig(String name) { +// super(name); +// } +// +// @Override +// public String toString() { +// return "SpanTracingConfig(" + name() + ")"; +// } +// +// /** +// * Merge configuration of two traced spans. +// * +// * @param older older span with default values +// * @param newer newer span overriding values in older +// * @return a new merged traced span configuration +// */ +// static SpanTracingConfig merge(SpanTracingConfig older, SpanTracingConfig newer) { +// return new SpanTracingConfig(newer.name()) { +// @Override +// public Optional newName() { +// return newer.newName() +// .or(older::newName); +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// +// @Override +// public Optional getSpanLog(String name) { +// Optional newLog = newer.getSpanLog(name); +// Optional oldLog = older.getSpanLog(name); +// +// if (newLog.isPresent() && oldLog.isPresent()) { +// return Optional.of(SpanLogTracingConfig.merge(oldLog.get(), newLog.get())); +// } +// +// if (newLog.isPresent()) { +// return newLog; +// } +// +// return oldLog; +// } +// }; +// } + + /** + * When rename is desired, returns the new name. + * + * @return new name for this span or empty when rename is not desired + */ + Optional newName(); + +// /** +// * Configuration of a traced span log. +// * +// * @param name name of the log event +// * @return configuration of the log event, or empty if not explicitly configured (used when merging) +// */ +// protected abstract Optional getSpanLog(String name); + + @Singular("spanLog") // B addSpanLog(String, FakeSpanLogTracingConfigBean); + Map spanLogMap(); + +// /** +// * Configuration of a traceable span log. +// * If this span is disabled, the log is always disabled. +// * +// * @param name name of the log event +// * @return configuration of the log event +// */ +// public final SpanLogTracingConfig spanLog(String name) { +// if (enabled()) { +// return getSpanLog(name).orElse(SpanLogTracingConfig.ENABLED); +// } else { +// return SpanLogTracingConfig.DISABLED; +// } +// } +// +// /** +// * Whether a log event should be logged on the span with a default value. +// * +// * @param logName name of the log event +// * @param defaultValue to use in case the log event is not configured in this span's configuration +// * @return whether to log ({@code true}) the event or not ({@code false}), uses the default value for unconfigured logs +// */ +// public boolean logEnabled(String logName, boolean defaultValue) { +// if (enabled()) { +// return getSpanLog(logName).map(Traceable::enabled).orElse(defaultValue); +// } +// return false; +// } +// +// /** +// * A fluent API builder to create traced span configuration. +// * +// * @param name name of the span +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create traced span configuration from a {@link io.helidon.config.Config}. +// * +// * @param name name of the span +// * @param config config to load span configuration from +// * @return a new traced span configuration +// */ +// public static SpanTracingConfig create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link SpanTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map spanLogMap = new HashMap<>(); +// private final String name; +// private Optional enabled = Optional.empty(); +// private String newName; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public SpanTracingConfig build() { +// final Map finalSpanLogMap = new HashMap<>(spanLogMap); +// final Optional finalNewName = Optional.ofNullable(newName); +// final Optional finalEnabled = enabled; +// +// return new SpanTracingConfig(name) { +// @Override +// public Optional newName() { +// return finalNewName; +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// +// @Override +// protected Optional getSpanLog(String name) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpanLogMap.get(name)); +// } +// return Optional.of(SpanLogTracingConfig.DISABLED); +// } +// }; +// } +// +// /** +// * Configure whether this traced span is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Configure a new name of this span. +// * +// * @param newName new name to use when reporting this span +// * @return updated builder instance +// */ +// public Builder newName(String newName) { +// this.newName = newName; +// return this; +// } +// +// /** +// * Add configuration of a traced span log. +// * +// * @param spanLogTracingConfig configuration of the traced span log +// * @return updated builder instance +// */ +// public Builder addSpanLog(SpanLogTracingConfig spanLogTracingConfig) { +// this.spanLogMap.put(spanLogTracingConfig.name(), spanLogTracingConfig); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of this span +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("new-name").asString().ifPresent(this::newName); +// config.get("logs") +// .asNodeList() +// .ifPresent(nodes -> { +// nodes.forEach(node -> { +// // name is mandatory +// addSpanLog(SpanLogTracingConfig.create(node.get("name").asString().get(), node)); +// }); +// }); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java new file mode 100644 index 00000000000..2a3d4a4e432 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java @@ -0,0 +1,55 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Optional; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka Traceable. + * Tracing configuration that can be enabled or disabled. + */ +@ConfigBean +public interface FakeTraceableConfig { + /** + * Whether this trace should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not, + * {@code empty} when this flag is not explicitly configured + */ + /*protected*/ Optional isEnabled(); + + /** + * Name of this traceable unit. + * + * @return name + */ + String name(); + + /** + * Whether this traceable should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not + */ + default boolean enabled() { + return isEnabled().orElse(true); + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java new file mode 100644 index 00000000000..a431c9d2801 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java @@ -0,0 +1,103 @@ +/* + * 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.pico.builder.config.fakes; + +/** + * Tracer abstraction. + * Tracer is the central point that collects tracing spans, and (probably) pushes them to backend. + */ +public interface FakeTracer { +// /** +// * Create a no-op tracer. All spans created from this tracer are not doing anything. +// * +// * @return no-op tracer +// */ +// static Tracer noOp() { +// return NoOpTracer.instance(); +// } +// +// /** +// * Get the currently registered global tracer. +// * +// * @return global tracer +// */ +// static Tracer global() { +// return TracerProviderHelper.global(); +// } +// +// /** +// * Register a global tracer, behavior depends on implementation. +// * +// * @param tracer tracer to use as a global tracer +// */ +// +// static void global(Tracer tracer) { +// TracerProviderHelper.global(tracer); +// } +// +// /** +// * Whether this tracer is enabled or not. +// * A no op tracer is disabled. +// * +// * @return {@code true} if this tracer is enabled +// */ +// boolean enabled(); +// +// /** +// * A new span builder to construct {@link io.helidon.tracing.Span}. +// * +// * @param name name of the operation +// * @return a new span builder +// */ +// Span.Builder spanBuilder(String name); +// +// /** +// * Extract parent span context from inbound request, such as from HTTP headers. +// * +// * @param headersProvider provider of headers +// * @return span context of inbound parent span, or empty optional if no span context can be found +// */ +// Optional extract(HeaderProvider headersProvider); +// +// /** +// * Inject current span as a parent for outbound request, such as when invoking HTTP request from a client. +// * +// * @param spanContext current span context +// * @param inboundHeadersProvider provider of inbound headers, may be {@link HeaderProvider#empty()} or headers from original +// * request (if any) +// * @param outboundHeadersConsumer consumer of headers that should be propagated to remote endpoint +// */ +// void inject(SpanContext spanContext, HeaderProvider inboundHeadersProvider, HeaderConsumer outboundHeadersConsumer); +// +// /** +// * Access the underlying tracer by specific type. +// * This is a dangerous operation that will succeed only if the tracer is of expected type. This practically +// * removes abstraction capabilities of this API. +// * +// * @param tracerClass type to access +// * @return instance of the tracer +// * @param type of the tracer +// * @throws java.lang.IllegalArgumentException in case the tracer cannot provide the expected type +// */ +// default T unwrap(Class tracerClass) { +// try { +// return tracerClass.cast(this); +// } catch (ClassCastException e) { +// throw new IllegalArgumentException("This tracer is not compatible with " + tracerClass.getName()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java new file mode 100644 index 00000000000..d99c5280f62 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java @@ -0,0 +1,245 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka TracingConfig. + * + * Tracing configuration that contains traced components (such as WebServer, Security) and their traced spans and span logs. + * Spans can be renamed through configuration, components, spans and span logs may be disabled through this configuration. + */ +@ConfigBean(key = "tracing") +public interface FakeTracingConfig extends FakeTraceableConfig { + +// /** +// * Traced config that is enabled for all components, spans and logs. +// */ +// FakeTracingConfig ENABLED = FakeTracingConfig.builder().build(); +// /** +// * Traced conifg that is disabled for all components, spans and logs. +// */ +// FakeTracingConfig DISABLED = FakeTracingConfig.builder().enabled(false).build(); + +// /** +// * A new traced configuration. +// * +// * @param name name of this configuration, when created using {@link FakeTracingConfig.Builder}, +// * the name is {@code helidon} +// */ +// protected FakeTracingConfig(String name) { +// super(name); +// } +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration or empty if defaults should be used +// */ +// protected abstract Optional getComponent(String componentName); +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration if configured, or an enabled component configuration +// */ +// public ComponentTracingConfig component(String componentName) { +// return component(componentName, true); +// } + + @Singular("component") // Builder::addComponent(String component); Impl::getComponent(String component); + Map components(); + +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @param enabledByDefault whether the component should be enabled or disabled in case it is not configured +// * @return component tracing configuration if configured, or an enabled/disabled component configuration depending on +// * {@code enabledByDefault} +// */ +// public ComponentTracingConfig component(String componentName, boolean enabledByDefault) { +// if (enabled()) { +// return getComponent(componentName) +// .orElseGet(() -> enabledByDefault ? ComponentTracingConfig.ENABLED : ComponentTracingConfig.DISABLED); +// } +// +// return ComponentTracingConfig.DISABLED; +// } +// +// @Override +// public String toString() { +// return "TracingConfig(" + name() + ")"; +// } +// +// /** +// * Create new tracing configuration based on the provided config. +// * +// * @param config configuration of tracing +// * @return tracing configuration +// */ +// public static FakeTracingConfig create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * A fluent API builder for tracing configuration. +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Merge two configurations together. +// * The result will combine configuration from both configurations. In case +// * of conflicts, the {@code newer} wins. +// * +// * @param older older instance to merge +// * @param newer newer (more significant) instance to merge +// * @return a new configuration combining odler and newer +// */ +// public static FakeTracingConfig merge(FakeTracingConfig older, FakeTracingConfig newer) { +// return new FakeTracingConfig(newer.name()) { +// @Override +// public Optional getComponent(String componentName) { +// Optional newerComponent = newer.getComponent(componentName); +// Optional olderComponent = older.getComponent(componentName); +// +// // both configured +// if (newerComponent.isPresent() && olderComponent.isPresent()) { +// return Optional.of(ComponentTracingConfig.merge(olderComponent.get(), newerComponent.get())); +// } +// +// // only newer configured +// if (newerComponent.isPresent()) { +// return newerComponent; +// } +// +// // only older configured +// return olderComponent; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Return configuration of a specific span. +// * This is a shortcut method to {@link #component(String)} and +// * {@link ComponentTracingConfig#span(String)}. +// * +// * @param component component, such as "web-server", "security" +// * @param spanName name of the span, such as "HTTP Request", "security:atn" +// * @return configuration of the span if present in this traced system configuration +// */ +// public SpanTracingConfig spanConfig(String component, String spanName) { +// return component(component).span(spanName); +// } + +// /** +// * Fluent API builder for {@link FakeTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map components = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// +// private Builder() { +// } +// +// @Override +// public FakeTracingConfig build() { +// return new RootTracingConfig("helidon", new HashMap<>(components), enabled); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config Config with tracing configuration +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// Config compConfig = config.get("components"); +// compConfig.asNodeList() +// .ifPresent(compList -> { +// compList.forEach(componentConfig -> addComponent(ComponentTracingConfig.create(componentConfig.name(), +// componentConfig))); +// }); +// +// return this; +// } +// +// /** +// * Add a traced component configuration. +// * +// * @param component configuration of this component's tracing +// * @return updated builder instance +// */ +// public Builder addComponent(ComponentTracingConfig component) { +// components.put(component.name(), component); +// return this; +// } +// +// /** +// * Whether overall tracing is enabled. +// * If tracing is disabled on this level, all traced components and spans are disabled - even if explicitly configured +// * as enabled. +// * +// * @param enabled set to {@code false} to disable tracing for any component and span +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +// +// static final class RootTracingConfig extends FakeTracingConfig { +// private final Map components; +// private final Optional enabled; +// +// RootTracingConfig(String name, +// Map components, +// Optional enabled) { +// super(name); +// this.components = components; +// this.enabled = enabled; +// } +// +// @Override +// public Optional getComponent(String componentName) { +// return Optional.ofNullable(components.get(componentName)); +// } +// +// @Override +// public Optional isEnabled() { +// return enabled; +// } +// +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java new file mode 100644 index 00000000000..3b3c7cadd6f --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java @@ -0,0 +1,56 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Objects; +import java.util.Optional; + +import jakarta.annotation.PostConstruct; +import jakarta.inject.Inject; + +//@ConfiguredBy(FakeServerConfig.class) +public class FakeWebServer implements WebServer { + + private FakeServerConfig cfg; + private boolean running; + + @Inject + FakeWebServer(FakeServerConfig cfg, Optional tracer) { + this.cfg = Objects.requireNonNull(cfg); + } + +// /** +// * The traditional approach. +// */ +// FakeWebServer(WebServer.Builder builder) { +// } + + @PostConstruct + public void initialize() { + running = true; + } + + @Override + public FakeServerConfig configuration() { + return cfg; + } + + @Override + public boolean isRunning() { + return running; + } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java new file mode 100644 index 00000000000..55df6d15b72 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java @@ -0,0 +1,437 @@ +/* + * 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.pico.builder.config.fakes; + +import java.security.SecureRandom; +import java.util.Collection; +import java.util.Random; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.common.LazyValue; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka WebServerTls. + * + * A class wrapping transport layer security (TLS) configuration for + * WebServer sockets. + */ +@ConfigBean +public interface FakeWebServerTlsConfig { + String PROTOCOL = "TLS"; + // secure random cannot be stored in native image, it must be initialized at runtime + LazyValue RANDOM = LazyValue.create(SecureRandom::new); + + /** + * This constant is a context classifier for the x509 client certificate if it is present. Callers may use this + * constant to lookup the client certificate associated with the current request context. + */ + String CLIENT_X509_CERTIFICATE = FakeWebServerTlsConfig.class.getName() + ".client-x509-certificate"; + +// private final Set enabledTlsProtocols; +// private final Set cipherSuite; +// private final SSLContext sslContext; +// private final boolean enabled; +// private final ClientAuthentication clientAuth; +// +// private FakeWebServerTlsConfigBean(Builder builder) { +// this.enabledTlsProtocols = Set.copyOf(builder.enabledTlsProtocols); +// this.cipherSuite = builder.cipherSuite; +// this.sslContext = builder.sslContext; +// this.enabled = (null != sslContext); +// this.clientAuth = builder.clientAuth; +// } +// +// /** +// * A fluent API builder for {@link FakeWebServerTlsConfigBean}. +// * +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create TLS configuration from config. +// * +// * @param config located on the node of the tls configuration (usually this is {@code ssl}) +// * @return a new TLS configuration +// */ +// public static FakeWebServerTlsConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// + Collection enabledTlsProtocols(); +// { +// return enabledTlsProtocols; +// } +// + + SSLContext sslContext(); +// { +// return sslContext; +// } + +// ClientAuthentication clientAuth() { +// return clientAuth; +// } + + @Singular("cipher") + Set cipherSuite(); +// { +// return cipherSuite; +// } + + /** + * Whether this TLS config has security enabled (and the socket is going to be + * protected by one of the TLS protocols), or no (and the socket is going to be plain). + * + * @return {@code true} if this configuration represents a TLS configuration, {@code false} for plain configuration + */ + boolean enabled(); +// { +// return enabled; +// } +// +// /** +// * Fluent API builder for {@link FakeWebServerTlsConfigBean}. +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private final Set enabledTlsProtocols = new HashSet<>(); +// +// private SSLContext sslContext; +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeoutSeconds; +// +// private boolean enabled; +// private Boolean explicitEnabled; +// private ClientAuthentication clientAuth; +// private Set cipherSuite = Set.of(); +// +// private Builder() { +// clientAuth = ClientAuthentication.NONE; +// } +// +// @Override +// public FakeWebServerTlsConfigBean build() { +// boolean enabled; +// +// if (null == explicitEnabled) { +// enabled = this.enabled; +// } else { +// enabled = explicitEnabled; +// } +// +// if (!enabled) { +// this.sslContext = null; +// // ssl is disabled +// return new FakeWebServerTlsConfigBean(this); +// } +// +// if (null == sslContext) { +// // no explicit ssl context, build it using private key and trust store +// sslContext = newSSLContext(); +// } +// +// return new FakeWebServerTlsConfigBean(this); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config config on the node of SSL configuration +// * @return this builder +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// if (explicitEnabled != null && !explicitEnabled) { +// return this; +// } +// +// config.get("client-auth").asString().ifPresent(this::clientAuth); +// config.get("private-key") +// .ifExists(it -> privateKey(FakeKeyConfig.create(it))); +// +// config.get("trust") +// .ifExists(it -> trust(FakeKeyConfig.create(it))); +// +// config.get("protocols").asList(String.class).ifPresent(this::enabledProtocols); +// config.get("session-cache-size").asLong().ifPresent(this::sessionCacheSize); +// config.get("cipher-suite").asList(String.class).ifPresent(this::allowedCipherSuite); +// DeprecatedConfig.get(config, "session-timeout-seconds", "session-timeout") +// .asLong() +// .ifPresent(this::sessionTimeoutSeconds); +// +// return this; +// } +// +// private void clientAuth(String it) { +// clientAuth(ClientAuthentication.valueOf(it.toUpperCase())); +// } +// +// /** +// * Configures whether client authentication will be required or not. +// * +// * @param clientAuth client authentication +// * @return this builder +// */ +// @ConfiguredOption("none") +// public Builder clientAuth(ClientAuthentication clientAuth) { +// this.clientAuth = Objects.requireNonNull(clientAuth); +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param context a SSL context to use +// * @return this builder +// */ +// public Builder sslContext(SSLContext context) { +// this.enabled = true; +// this.sslContext = context; +// return this; +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * @param protocols protocols to enable, if empty, enables defaults +// * +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(String... protocols) { +// return enabledProtocols(Arrays.asList(Objects.requireNonNull(protocols))); +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * +// * @param protocols protocols to enable, if empty enables +// * the default protocols +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(Collection protocols) { +// Objects.requireNonNull(protocols); +// +// this.enabledTlsProtocols.clear(); +// this.enabledTlsProtocols.addAll(protocols); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// @ConfiguredOption(required = true) +// public Builder privateKey(FakeKeyConfig privateKeyConfig) { +// // setting private key, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.privateKeyConfig = Objects.requireNonNull(privateKeyConfig); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfigBuilder the required private key configuration parameter +// * @return this builder +// */ +// public Builder privateKey(Supplier privateKeyConfigBuilder) { +// return privateKey(privateKeyConfigBuilder.get()); +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return this builder +// */ +// @ConfiguredOption +// public Builder trust(FakeKeyConfig trustConfig) { +// // setting explicit trust, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.trustConfig = Objects.requireNonNull(trustConfig); +// return this; +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfigBuilder the trust configuration builder +// * @return this builder +// */ +// public Builder trust(Supplier trustConfigBuilder) { +// return trust(trustConfigBuilder.get()); +// } +// +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionTimeoutSeconds(long sessionTimeout) { +// this.sessionTimeoutSeconds = sessionTimeout; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param timeout the session timeout amount +// * @param unit the session timeout time unit +// * @return this builder +// */ +// public Builder sessionTimeout(long timeout, TimeUnit unit) { +// this.sessionTimeoutSeconds = unit.toSeconds(timeout); +// return this; +// } +// +// /** +// * Set allowed cipher suite. If an empty collection is set, an exception is thrown since +// * it is required to support at least some ciphers. +// * +// * @param cipherSuite allowed cipher suite +// * @return an updated builder +// */ +// @ConfiguredOption(key = "cipher-suite") +// public Builder allowedCipherSuite(List cipherSuite) { +// Objects.requireNonNull(cipherSuite); +// if (cipherSuite.isEmpty()) { +// throw new IllegalStateException("Allowed cipher suite has to have at least one cipher specified"); +// } +// this.cipherSuite = Set.copyOf(cipherSuite); +// return this; +// } +// +// /** +// * Whether the TLS config should be enabled or not. +// * +// * @param enabled configure to {@code false} to disable SSL context (and SSL support on the server) +// * @return this builder +// */ +// @ConfiguredOption(description = "Can be used to disable TLS even if keys are configured.", value = "true") +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// this.explicitEnabled = enabled; +// return this; +// } +// +// private SSLContext newSSLContext() { +// try { +// if (null == privateKeyConfig) { +// throw new IllegalStateException("Private key must be configured when SSL is enabled."); +// } +// KeyManagerFactory kmf = buildKmf(this.privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(this.trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (this.sessionTimeoutSeconds > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeoutSeconds, Integer.MAX_VALUE)); +// } +// return ctx; +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Failed to build server SSL Context!", e); +// } +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.get().nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java new file mode 100644 index 00000000000..760b0942b74 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java @@ -0,0 +1,204 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Random; + +import io.helidon.pico.builder.Builder; + +/** + * aka SSLContextBuilder. + * Note that this is just a normal builder, and will not be integrated with Config. + * Builder for configuring a new SslContext for creation. + */ +@Builder +public interface SSLContextConfig { + + String PROTOCOL = "TLS"; + Random RANDOM = new Random(); + +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeout; +// +// private SSLContextConfig() { +// } +// + +// /** +// * Creates a builder of the {@link javax.net.ssl.SSLContext}. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// public static SSLContextConfig create(FakeKeyConfig privateKeyConfig) { +// return new SSLContextConfig().privateKeyConfig(privateKeyConfig); +// } + +// /** +// * Creates {@link javax.net.ssl.SSLContext} from the provided configuration. +// * +// * @param sslConfig the ssl configuration +// * @return a built {@link javax.net.ssl.SSLContext} +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// static SSLContext create(Config sslConfig) { +// return new SSLContextConfig().privateKeyConfig(FakeKeyConfig.create(sslConfig.get("private-key"))) +// .sessionCacheSize(sslConfig.get("session-cache-size").asInt().orElse(0)) +// .sessionTimeout(sslConfig.get("session-timeout").asInt().orElse(0)) +// .trustConfig(FakeKeyConfig.create(sslConfig.get("trust"))) +// .build(); +// } +// +// private SSLContextConfig privateKeyConfig(FakeKeyConfig privateKeyConfig) { +// this.privateKeyConfig = privateKeyConfig; +// return this; +// } + + FakeKeyConfig privateKeyConfig(); + +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return an updated builder +// */ +// public SSLContextConfig trustConfig(FakeKeyConfig trustConfig) { +// this.trustConfig = trustConfig; +// return this; +// } + + FakeKeyConfig trustConfig(); + +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return an updated builder +// */ +// public SSLContextConfig sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } + + long sessionCacheSize(); + +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return an updated builder +// */ +// public SSLContextConfig sessionTimeout(long sessionTimeout) { +// this.sessionTimeout = sessionTimeout; +// return this; +// } + + long sessionTimeout(); + +// /** +// * Create new {@code {@link javax.net.ssl.SSLContext}} instance with configured settings. +// * +// * @return the SSL Context built instance +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// public SSLContext build() { +// Objects.requireNonNull(privateKeyConfig, "The private key config must be set!"); +// +// try { +// return newSSLContext(privateKeyConfig, trustConfig, sessionCacheSize, sessionTimeout); +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Building of the SSLContext of unsuccessful!", e); +// } +// } + + // re-enable this. +// private static SSLContext newSSLContext(FakeKeyConfig privateKeyConfig, +// FakeKeyConfig trustConfig, +// long sessionCacheSize, +// long sessionTimeout) +// throws IOException, GeneralSecurityException { +// KeyManagerFactory kmf = buildKmf(privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (sessionTimeout > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE)); +// } +// return ctx; +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java new file mode 100644 index 00000000000..0da8c238531 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java @@ -0,0 +1,773 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Objects; + +import io.helidon.pico.Contract; + +@Contract +public interface WebServer { + + String DEFAULT_SOCKET_NAME = "@default"; + + /** + * Gets effective server configuration. + * + * @return Server configuration + */ + FakeServerConfig configuration(); + +// /** +// * Starts the server. Has no effect if server is running. +// * The start will fail on a server that is shut down, or that failed to start. +// * In such cases, create a new instance of Web Server. +// * +// * @return a single to react on startup process +// */ +// Single start(); +// +// /** +// * Completion stage is completed when server is shut down. +// * +// * @return a completion stage of the server +// */ +// Single whenShutdown(); +// +// /** +// * Attempt to gracefully shutdown server. It is possible to use returned {@link io.helidon.common.reactive.Single} to react. +// *

+// * RequestMethod can be called periodically. +// * +// * @return a single to react on finished shutdown process +// * @see #start() +// */ +// Single shutdown(); + + /** + * Returns {@code true} if the server is currently running. Running server in stopping phase returns {@code true} until it + * is not fully stopped. + * + * @return {@code true} if server is running + */ + boolean isRunning(); + +// /** +// * Gets a {@link WebServer} context. +// * +// * @return a server context +// */ +// Context context(); +// +// /** +// * Get the parent {@link MessageBodyReaderContext} context. +// * +// * @return media body reader context +// */ +// MessageBodyReaderContext readerContext(); +// +// /** +// * Get the parent {@link MessageBodyWriterContext} context. +// * +// * @return media body writer context +// */ +// MessageBodyWriterContext writerContext(); + + /** + * Returns a port number the default server socket is bound to and is listening on; + * or {@code -1} if unknown or not active. + *

+ * It is supported only when server is running. + * + * @return a listen port; or {@code -1} if unknown or the default server socket is not active + */ +// default int port() { +// return port(WebServer.DEFAULT_SOCKET_NAME); +// } + + /** + * Returns a port number an additional named server socket is bound to and is listening on; + * or {@code -1} if unknown or not active. + * + * @param socketName the name of an additional named server socket + * @return a listen port; or {@code -1} if socket name is unknown or the server socket is not active + */ + // based on runtime +// default int port(String socketName) { +// if (!isRunning()) { +// return -1; +// } +// +// FakeSocketConfig cfg = configuration().sockets().get(socketName); +// return (Objects.isNull(cfg)) ? -1 : cfg.port(); +// } + + /** + * Returns {@code true} if TLS is configured for the default socket. + * + * @return whether TLS is enabled for the default socket + */ + default boolean hasTls() { + return hasTls(WebServer.DEFAULT_SOCKET_NAME); + } + + /** + * Returns {@code true} if TLS is configured for the named socket. + * + * @param socketName the name of a socket + * @return whether TLS is enabled for the socket, returns {@code false} if the socket does not exists + */ + default boolean hasTls(String socketName) { + FakeSocketConfig cfg = configuration().sockets().get(socketName); + return !Objects.isNull(cfg) && cfg.tls().isPresent(); + } + +// /** +// * Update the TLS configuration of the default socket {@link WebServer#DEFAULT_SOCKET_NAME}. +// * +// * @param tls new TLS configuration +// * @throws IllegalStateException if {@link WebServerTls#enabled()} returns {@code false} or +// * if {@code SocketConfiguration.tls().sslContext()} returns {@code null} +// */ +// void updateTls(WebServerTls tls); +// +// /** +// * Update the TLS configuration of the named socket. +// * +// * @param tls new TLS configuration +// * @param socketName specific named socket name +// * @throws IllegalStateException if {@link WebServerTls#enabled()} returns {@code false} or +// * if {@code SocketConfiguration.tls().sslContext()} returns {@code null} +// */ +// void updateTls(WebServerTls tls, String socketName); +// +// /** +// * Creates new instance from provided routing and default configuration. +// * +// * @param routing a routing instance +// * @return a new web server instance +// * @throws IllegalStateException if none SPI implementation found +// * @throws NullPointerException if 'routing' parameter is {@code null} +// */ +// static WebServer create(Routing routing) { +// return builder(routing).build(); +// } +// +// /** +// * Creates new instance from provided configuration and routing. +// * +// * @param routing a routing instance +// * @param config configuration located on server configuration node +// * @return a new web server instance +// * @throws NullPointerException if 'routing' parameter is {@code null} +// * +// * @since 2.0.0 +// */ +// static WebServer create(Routing routing, Config config) { +// return builder(routing) +// .config(config) +// .build(); +// } +// +// /** +// * Creates new instance from provided configuration and routing. +// * +// * @param routingBuilder a supplier of routing (such as {@link Routing.Builder} +// * @param config configuration located on server configuration node +// * @return a new web server instance +// * @throws NullPointerException if 'routing' parameter is {@code null} +// * +// * @since 2.0.0 +// */ +// static WebServer create(Supplier routingBuilder, Config config) { +// return builder(routingBuilder.get()) +// .config(config) +// .build(); +// } +// +// /** +// * Creates new instance from provided routing and default configuration. +// * +// * @param routingBuilder a routing builder instance that will be built as a first step +// * of this method execution +// * @return a new web server instance +// * @throws IllegalStateException if none SPI implementation found +// * @throws NullPointerException if 'routing' parameter is {@code null} +// */ +// static WebServer create(Supplier routingBuilder) { +// Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!"); +// return create(routingBuilder.get()); +// } + +// /** +// * Creates a builder of the {@link WebServer}. +// * +// * @param routingBuilder the routing builder; must not be {@code null} +// * @return the builder +// */ +// static Builder builder(Supplier routingBuilder) { +// Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!"); +// return builder(routingBuilder.get()); +// } +// +// /** +// * Creates a fluent API builder of the {@link io.helidon.webserver.WebServer}. +// * Before calling the {@link io.helidon.webserver.WebServer.Builder#build()} method, you should +// * configure the default routing. If none is configured, all requests will end in {@code 404}. +// * +// * @return a new builder +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Creates a builder of the {@link WebServer}. +// * +// * @param routing the routing to use for the default port; must not be {@code null} +// * @return the builder +// * @see #builder() +// */ +// static Builder builder(Routing routing) { +// return builder().addRouting(routing); +// } +// +// /** +// * WebServer builder class provides a convenient way to set up WebServer with multiple server +// * sockets and optional multiple routings. +// */ +// @Configured(root = true, prefix = "server", description = "Configuration of the HTTP server.") +// final class Builder implements io.helidon.common.Builder, +// FakeSocketConfigBean.SocketConfigurationBuilder, +// ParentingMediaContextBuilder, +// MediaContextBuilder { +// +// private static final Logger LOGGER = Logger.getLogger(Builder.class.getName()); +// private static final MediaContext DEFAULT_MEDIA_SUPPORT = MediaContext.create(); +// private final Map routingBuilders = new HashMap<>(); +// private final DirectHandlers.Builder directHandlers = DirectHandlers.builder(); +// // internal use - we may keep this even after we remove the public access to ServerConfiguration +// @SuppressWarnings("deprecation") +// private final FakeServerConfigBean.Builder configurationBuilder = FakeServerConfigBean.builder(); +// // for backward compatibility +// @SuppressWarnings("deprecation") +// private FakeServerConfigBean explicitConfig; +// private MessageBodyReaderContext readerContext; +// private MessageBodyWriterContext writerContext; +// +// private Builder() { +// readerContext = MessageBodyReaderContext.create(DEFAULT_MEDIA_SUPPORT.readerContext()); +// writerContext = MessageBodyWriterContext.create(DEFAULT_MEDIA_SUPPORT.writerContext()); +// } +// +// /** +// * Builds the {@link WebServer} instance as configured by this builder and its parameters. +// * +// * @return a ready to use {@link WebServer} +// * @throws IllegalStateException if there are unpaired named routings (as described +// * at {@link #addNamedRouting(String, Routing)}) +// */ +// @Override +// public WebServer build() { +// if (routingBuilders.get(WebServer.DEFAULT_SOCKET_NAME) == null) { +// LOGGER.warning("Creating a web server with no default routing configured."); +// routingBuilders.put(WebServer.DEFAULT_SOCKET_NAME, RouterImpl.builder()); +// } +// if (explicitConfig == null) { +// explicitConfig = configurationBuilder.build(); +// } +// +// Map routers = routingBuilders.entrySet().stream() +// .collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().build())); +// +// String unpairedRoutings = +// routingBuilders.keySet() +// .stream() +// .filter(routingName -> explicitConfig.namedSocket(routingName).isEmpty()) +// .collect(Collectors.joining(", ")); +// +// if (!unpairedRoutings.isEmpty()) { +// throw new IllegalStateException("No server socket configuration found for named routings: " + unpairedRoutings); +// } +// +// routers.values().forEach(Router::beforeStart); +// +// WebServer result = new NettyWebServer(explicitConfig, +// routers, +// writerContext, +// readerContext, +// directHandlers.build()); +// +// RequestRouting defaultRouting = routers.get(WebServer.DEFAULT_SOCKET_NAME).routing(RequestRouting.class, null); +// +// if (defaultRouting != null) { +// defaultRouting.fireNewWebServer(result); +// } +// return result; +// } +// +// /** +// * Configure listener for the default socket. +// * +// * @param socket socket configuration builder consumer +// * @return updated builder +// */ +// public Builder defaultSocket(Consumer socket){ +// socket.accept(this.configurationBuilder.defaultSocketBuilder()); +// return this; +// } +// +// /** +// * Configure the transport to be used by this server. +// * +// * @param transport transport to use +// * @return updated builder instance +// */ +// public Builder transport(Transport transport) { +// configurationBuilder.transport(transport); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param defaultRouting new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// * @deprecated Use {@link WebServer.Builder#addRouting(Routing)} +// * or {@link WebServer.Builder#addRouting(Routing)} instead. +// */ +// @Deprecated(since = "3.0.0", forRemoval = true) +// public Builder routing(Routing defaultRouting) { +// addRouting(defaultRouting); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param routing new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder addRouting(Routing routing) { +// Objects.requireNonNull(routing); +// routingBuilders.computeIfAbsent(WebServer.DEFAULT_SOCKET_NAME, s -> RouterImpl.builder()) +// .addRouting(routing); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param routingSupplier new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder addRouting(Supplier routingSupplier) { +// Objects.requireNonNull(routingSupplier); +// addRouting(routingSupplier.get()); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param defaultRouting new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder routing(Supplier defaultRouting) { +// addRouting(Objects.requireNonNull(defaultRouting).get()); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param routing new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder routing(Consumer routing) { +// Routing.Builder builder = Routing.builder(); +// Objects.requireNonNull(routing).accept(builder); +// routingBuilders.computeIfAbsent(WebServer.DEFAULT_SOCKET_NAME, s -> RouterImpl.builder()) +// .addRoutingBuilder(RequestRouting.class, builder); +// return this; +// } +// +// /** +// * Update this server configuration from the config provided. +// * +// * @param config config located on server node +// * @return an updated builder +// * @since 2.0.0 +// */ +// public Builder config(Config config) { +// this.configurationBuilder.config(config); +// return this; +// } +// +// /** +// * Associates a dedicated routing with an additional server socket configuration. +// *

+// * The additional server socket configuration must be set as per +// * {@link io.helidon.pico.config.fake.helidon.config.FakeServerConfigBean.Builder#addSocket(String, io.helidon.pico.config.fake.helidon.config.FakeSocketConfigBean)}. If there is no such +// * named server socket configuration, a {@link IllegalStateException} is thrown by the +// * {@link #build()} method. +// * +// * @param name the named server socket configuration to associate the provided routing with +// * @param routing the routing to associate with the provided name of a named server socket +// * configuration +// * @return an updated builder +// */ +// public Builder addNamedRouting(String name, Routing routing) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// Objects.requireNonNull(routing, "Parameter 'routing' must not be null!"); +// routingBuilders.computeIfAbsent(name, s -> RouterImpl.builder()) +// .addRouting(routing); +// return this; +// } +// +// /** +// * Associates a dedicated routing with an additional server socket configuration. +// *

+// * The additional server socket configuration must be set as per +// * {@link io.helidon.pico.config.fake.helidon.config.FakeServerConfigBean.Builder#addSocket(String, io.helidon.pico.config.fake.helidon.config.FakeSocketConfigBean)}. If there is no such +// * named server socket configuration, a {@link IllegalStateException} is thrown by the +// * {@link #build()} method. +// * +// * @param name the named server socket configuration to associate the provided routing with +// * @param routingBuilder the routing builder to associate with the provided name of a named server socket +// * configuration; will be built as a first step of this method execution +// * @return an updated builder +// */ +// public Builder addNamedRouting(String name, Supplier routingBuilder) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!"); +// +// return addNamedRouting(name, routingBuilder.get()); +// } +// +// @Override +// public Builder mediaContext(MediaContext mediaContext) { +// Objects.requireNonNull(mediaContext); +// this.readerContext = MessageBodyReaderContext.create(mediaContext.readerContext()); +// this.writerContext = MessageBodyWriterContext.create(mediaContext.writerContext()); +// return this; +// } +// +// @Override +// public Builder addMediaSupport(MediaSupport mediaSupport) { +// Objects.requireNonNull(mediaSupport); +// mediaSupport.register(readerContext, writerContext); +// return this; +// } +// +// @Override +// public Builder addReader(MessageBodyReader reader) { +// readerContext.registerReader(reader); +// return this; +// } +// +// @Override +// public Builder addStreamReader(MessageBodyStreamReader streamReader) { +// readerContext.registerReader(streamReader); +// return this; +// } +// +// @Override +// public Builder addWriter(MessageBodyWriter writer) { +// writerContext.registerWriter(writer); +// return this; +// } +// +// @Override +// public Builder addStreamWriter(MessageBodyStreamWriter streamWriter) { +// writerContext.registerWriter(streamWriter); +// return this; +// } +// +// @Override +// public Builder port(int port) { +// configurationBuilder.port(port); +// return this; +// } +// +// @Override +// public Builder bindAddress(InetAddress bindAddress) { +// configurationBuilder.bindAddress(bindAddress); +// return this; +// } +// +// @Override +// public Builder backlog(int backlog) { +// configurationBuilder.backlog(backlog); +// return this; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// configurationBuilder.timeout(amount, unit); +// return this; +// } +// +// @Override +// public Builder receiveBufferSize(int receiveBufferSize) { +// configurationBuilder.receiveBufferSize(receiveBufferSize); +// return this; +// } +// +// @Override +// public Builder tls(WebServerTls webServerTls) { +// configurationBuilder.tls(webServerTls); +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// configurationBuilder.maxHeaderSize(size); +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// configurationBuilder.maxInitialLineLength(length); +// return this; +// } +// +// @Override +// public Builder enableCompression(boolean value) { +// configurationBuilder.enableCompression(value); +// return this; +// } +// +// @Override +// public Builder maxPayloadSize(long size) { +// configurationBuilder.maxPayloadSize(size); +// return this; +// } +// +// @Override +// public Builder maxUpgradeContentLength(int size) { +// configurationBuilder.maxUpgradeContentLength(size); +// return this; +// } +// +// /** +// * A helper method to support fluentAPI when invoking another method. +// *

+// * Example: +// *

+//         *     WebServer.Builder builder = WebServer.builder();
+//         *     updateBuilder(builder);
+//         *     return builder.build();
+//         * 
+// * Can be changed to: +// *
+//         *     return WebServer.builder()
+//         *              .update(this::updateBuilder)
+//         *              .build();
+//         * 
+// * +// * +// * @param updateFunction function to update this builder +// * @return an updated builder +// */ +// public Builder update(Consumer updateFunction) { +// updateFunction.accept(this); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param config the additional named server socket configuration, never null +// * @return an updated builder +// */ +// @ConfiguredOption(key = "sockets", kind = ConfiguredOption.Kind.LIST) +// public Builder addSocket(FakeSocketConfigBean config) { +// configurationBuilder.addSocket(config.name(), config); +// return this; +// } +// +// /** +// * Adds or augment existing named server socket configuration. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name socket name +// * @param socket new or existing configuration builder +// * @return an updated builder +// */ +// public Builder socket(String name, Consumer socket) { +// socket.accept(configurationBuilder.socketBuilder(name)); +// return this; +// } +// +// /** +// * Adds or augment existing named server socket configuration. +// *

+// * An additional named server socket have a dedicated {@link Routing} configured +// * through supplied routing builder. +// * +// * @param socketName socket name +// * @param builders consumer with socket configuration and dedicated routing builders +// * @return an updated builder +// */ +// public Builder socket(String socketName, BiConsumer builders) { +// builders.accept( +// this.configurationBuilder.socketBuilder(socketName), +// routingBuilders.computeIfAbsent(socketName, s -> RouterImpl.builder()) +// ); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration builder. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as +// * a first step of this method execution +// * @return an updated builder +// */ +// public Builder addSocket(Supplier socketConfigurationBuilder) { +// FakeSocketConfigBean socketConfiguration = socketConfigurationBuilder.get(); +// +// configurationBuilder.addSocket(socketConfiguration.name(), socketConfiguration); +// return this; +// } +// +// /** +// * Add a named socket and routing. +// * +// * @param socketConfiguration named configuration of the socket +// * @param routing routing to use for this socket +// * +// * @return an updated builder +// */ +// public Builder addSocket(FakeSocketConfigBean socketConfiguration, Routing routing) { +// addSocket(socketConfiguration); +// addNamedRouting(socketConfiguration.name(), routing); +// return this; +// } +// +// +// /** +// * Sets a tracer. +// * +// * @param tracer a tracer to set +// * @return an updated builder +// */ +// public Builder tracer(Tracer tracer) { +// configurationBuilder.tracer(tracer); +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution +// * @return updated builder +// */ +// public Builder tracer(Supplier tracerBuilder) { +// configurationBuilder.tracer(tracerBuilder); +// return this; +// } +// +// /** +// * A method to validate a named socket configuration exists in this builder. +// * +// * @param socketName name of the socket, using {@link io.helidon.webserver.WebServer#DEFAULT_SOCKET_NAME} +// * will always return {@code true} +// * @return {@code true} in case the named socket is configured in this builder +// */ +// public boolean hasSocket(String socketName) { +// return DEFAULT_SOCKET_NAME.equals(socketName) +// || configurationBuilder.sockets().containsKey(socketName); +// } +// +// /** +// * Configure the application scoped context to be used as a parent for webserver request contexts. +// * @param context top level context +// * @return an updated builder +// */ +// public Builder context(Context context) { +// configurationBuilder.context(context); +// return this; +// } +// +// /** +// * Sets a count of threads in pool used to process HTTP requests. +// * Default value is {@code CPU_COUNT * 2}. +// *

+// * Configuration key: {@code workers} +// * +// * @param workers a workers count +// * @return an updated builder +// */ +// @ConfiguredOption(key = "worker-count") +// public Builder workersCount(int workers) { +// configurationBuilder.workersCount(workers); +// return this; +// } +// +// /** +// * Set to {@code true} to print detailed feature information on startup. +// * +// * @param shouldPrint whether to print details or not +// * @return updated builder instance +// * @see io.helidon.common.HelidonFeatures +// */ +// @ConfiguredOption(key = "features.print-details", value = "false") +// public Builder printFeatureDetails(boolean shouldPrint) { +// configurationBuilder.printFeatureDetails(shouldPrint); +// return this; +// } +// +// /** +// * Provide a custom handler for events that bypass routing. +// * The handler can customize status, headers and message. +// *

+// * Examples of bad request ({@link DirectHandler.EventType#BAD_REQUEST}: +// *

    +// *
  • Invalid character in path
  • +// *
  • Content-Length header set to a non-integer value
  • +// *
  • Invalid first line of the HTTP request
  • +// *
+// * @param handler direct handler to use +// * @param types event types to handle with the provided handler +// * @return updated builder +// */ +// public Builder directHandler(DirectHandler handler, DirectHandler.EventType... types) { +// for (DirectHandler.EventType type : types) { +// directHandlers.addHandler(type, handler); +// } +// +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java new file mode 100644 index 00000000000..1f6fb1a11a7 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes.config; + +/** + * Indicates whether the server requires authentication of tbe client by the certificate. + */ +public enum FakeClientAuth { + + /** + * Authentication is required. + */ + REQUIRE(FakeNettyClientAuth.REQUIRE), + + /** + * Authentication is optional. + */ + OPTIONAL(FakeNettyClientAuth.OPTIONAL), + + /** + * Authentication is not required. + */ + NONE(FakeNettyClientAuth.NONE); + + private final FakeNettyClientAuth clientAuth; + + FakeClientAuth(FakeNettyClientAuth clientAuth) { + this.clientAuth = clientAuth; + } + + FakeNettyClientAuth nettyClientAuth(){ + return clientAuth; + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java new file mode 100644 index 00000000000..182690407bc --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java @@ -0,0 +1,223 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ComponentTracing. + */ +@ConfigBean +public interface FakeComponentTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled component - all subsequent calls return disabled spans and logs. +// */ +// public static final ComponentTracingConfig DISABLED = ComponentTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * Enabled component - all subsequent calls return enabled spans and logs. +// */ +// public static final ComponentTracingConfig ENABLED = ComponentTracingConfig.builder("enabled").build(); + +// /** +// * A new named component. +// * +// * @param name name of the component +// */ +// protected ComponentTracingConfig(String name) { +// super(name); +// } +// + +// /** +// * Merge configuration of two traced components. This enabled hierarchical configuration +// * with common, default configuration in one traced component and override in another. +// * +// * @param older the older configuration with "defaults" +// * @param newer the newer configuration to override defaults in older +// * @return merged component +// */ +// static ComponentTracingConfig merge(ComponentTracingConfig older, ComponentTracingConfig newer) { +// return new ComponentTracingConfig(newer.name()) { +// @Override +// public Optional getSpan(String spanName) { +// if (!enabled()) { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// +// Optional newSpan = newer.getSpan(spanName); +// Optional oldSpan = older.getSpan(spanName); +// +// // both configured +// if (newSpan.isPresent() && oldSpan.isPresent()) { +// return Optional.of(SpanTracingConfig.merge(oldSpan.get(), newSpan.get())); +// } +// +// // only newer +// if (newSpan.isPresent()) { +// return newSpan; +// } +// +// return oldSpan; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of the span in this component +// * @return configuration of that span if present +// */ +// protected abstract Optional getSpan(String spanName); +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @return configuration of the span, or enabled configuration if not configured +// * @see #span(String, boolean) +// */ +// public SpanTracingConfig span(String spanName) { +// return span(spanName, true); +// } + + @Singular("span") // Builder::addSpan(String span, FakeSpanLogTracingConfigBean val), Impl::getSpan(String span), etc. + Map spanLogMap(); + +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @param enabledByDefault whether the result is enabled if a configuration is not present +// * @return configuration of the span, or a span configuration enabled or disabled depending on {@code enabledByDefault} if +// * not configured +// */ +// public SpanTracingConfig span(String spanName, boolean enabledByDefault) { +// if (enabled()) { +// return getSpan(spanName).orElseGet(() -> enabledByDefault ? SpanTracingConfig.ENABLED : SpanTracingConfig.DISABLED); +// } +// +// return SpanTracingConfig.DISABLED; +// } +// +// /** +// * Fluent API builder for traced component. +// * +// * @param name the name of the component +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced component configuration from {@link Config}. +// * +// * @param name name of the component +// * @param config config for a new component +// * @return a new traced component configuration +// */ +// public static ComponentTracingConfig create(String name, Config config) { +// return builder(name) +// .config(config) +// .build(); +// } +// +// /** +// * Fluent API builder for {@link ComponentTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map tracedSpans = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// private final String name; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public ComponentTracingConfig build() { +// // immutability +// final Optional finalEnabled = enabled; +// final Map finalSpans = new HashMap<>(tracedSpans); +// return new ComponentTracingConfig(name) { +// @Override +// public Optional getSpan(String spanName) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpans.get(spanName)); +// } else { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of a traced component +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("spans").asNodeList().ifPresent(spanConfigList -> { +// spanConfigList.forEach(spanConfig -> { +// // span name is mandatory +// addSpan(SpanTracingConfig.create(spanConfig.get("name").asString().get(), spanConfig)); +// }); +// }); +// return this; +// } +// +// /** +// * Add a new traced span configuration. +// * +// * @param span configuration of a traced span +// * @return updated builder instance +// */ +// public Builder addSpan(SpanTracingConfig span) { +// this.tracedSpans.put(span.name(), span); +// return this; +// } +// +// /** +// * Configure whether this component is enabled or disabled. +// * +// * @param enabled if disabled, all spans and logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java new file mode 100644 index 00000000000..3adb14006fc --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java @@ -0,0 +1,839 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * aka KeyConfig. + * + */ +@Builder +public interface FakeKeyConfig { + + // /*private static final*/ String DEFAULT_PRIVATE_KEY_ALIAS = "1"; +// /*private static final*/ char[] EMPTY_CHARS = new char[0]; + +// private static final Logger LOGGER = Logger.getLogger(FakeKeyConfigBean.class.getName()); +// +// private final PrivateKey privateKey; +// private final PublicKey publicKey; +// private final X509Certificate publicCert; +// private final List certChain = new LinkedList<>(); +// private final List certificates = new LinkedList<>(); +// +// private FakeKeyConfigBean(PrivateKey privateKey, +// PublicKey publicKey, +// X509Certificate publicCert, +// Collection certChain, +// Collection certificates) { +// +// this.privateKey = privateKey; +// this.publicKey = publicKey; +// this.publicCert = publicCert; +// this.certChain.addAll(certChain); +// this.certificates.addAll(certificates); +// } +// +// /** +// * Load key config from config. +// * +// * @param config config instance located at keys configuration (expects "keystore-path" child) +// * @return KeyConfig loaded from config +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// public static FakeKeyConfigBean create(Config config) throws PkiException { +// try { +// return fullBuilder().config(config).build(); +// } catch (ResourceException e) { +// throw new PkiException("Failed to load from config", e); +// } +// } +// +// /** +// * Creates a new builder to configure instance. +// * +// * @return builder instance +// */ +// public static Builder fullBuilder() { +// return new Builder(); +// } +// +// /** +// * Build this instance from PEM files (usually a pair of private key and certificate chain). +// * Call {@link PemBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for PEM files +// */ +// public static PemBuilder pemBuilder() { +// return new PemBuilder(); +// } +// +// /** +// * Build this instance from a java keystore (such as PKCS12 keystore). +// * Call {@link KeystoreBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for Keystore +// */ +// public static KeystoreBuilder keystoreBuilder() { +// return new KeystoreBuilder(); +// } +// + /** + * The public key of this config if configured. + * + * @return the public key of this config or empty if not configured + */ + /*public*/ Optional publicKey(); +// { +// return Optional.ofNullable(publicKey); +// } + + /** + * The private key of this config if configured. + * + * @return the private key of this config or empty if not configured + */ + /*public*/ Optional privateKey(); +// { +// return Optional.ofNullable(privateKey); +// } + + /** + * The public X.509 Certificate if configured. + * + * @return the public certificate of this config or empty if not configured + */ + /*public*/ Optional publicCert(); +// { +// return Optional.ofNullable(publicCert); +// } + + /** + * The X.509 Certificate Chain. + * + * @return the certificate chain or empty list if not configured + */ + /*public*/ List certChain(); +// { +// return Collections.unmodifiableList(certChain); +// } + + /** + * The X.509 Certificates. + * + * @return the certificates configured or empty list if none configured + */ + /*public*/ List certs(); +// { +// return Collections.unmodifiableList(certificates); +// } + + +// public DefaultFakeConfigBean.Builder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + + +// /** +// * Fluent API builder for {@link FakeKeyConfigBean}. +// * Call {@link #build()} to create an instance. +// * +// * The keys may be loaded from multiple possible sources. +// * +// * @see FakeKeyConfigBean#keystoreBuilder() +// * @see FakeKeyConfigBean#pemBuilder() +// * @see FakeKeyConfigBean#fullBuilder() +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private PrivateKey explicitPrivateKey; +// private PublicKey explicitPublicKey; +// private X509Certificate explicitPublicCert; +// private final List explicitCertChain = new LinkedList<>(); +// private final List explicitCertificates = new LinkedList<>(); +// +// /** +// * Build a new instance of the configuration based on this builder. +// * +// * @return instance from this builder +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// @Override +// public FakeKeyConfigBean build() throws PkiException { +// PrivateKey privateKey = this.explicitPrivateKey; +// PublicKey publicKey = this.explicitPublicKey; +// X509Certificate publicCert = this.explicitPublicCert; +// List certChain = new LinkedList<>(explicitCertChain); +// List certificates = new LinkedList<>(explicitCertificates); +// +// // fix public key if cert is provided +// if (null == publicKey && null != publicCert) { +// publicKey = publicCert.getPublicKey(); +// } +// +// return new FakeKeyConfigBean(privateKey, publicKey, publicCert, certChain, certificates); +// } +// +// /** +// * Configure a private key instance (rather then keystore and alias). +// * +// * @param privateKey private key instance +// * @return updated builder instance +// */ +// public Builder privateKey(PrivateKey privateKey) { +// this.explicitPrivateKey = privateKey; +// return this; +// } +// +// /** +// * Configure a public key instance (rather then keystore and certificate alias). +// * +// * @param publicKey private key instance +// * @return updated builder instance +// */ +// public Builder publicKey(PublicKey publicKey) { +// this.explicitPublicKey = publicKey; +// return this; +// } +// +// /** +// * Configure an X.509 certificate instance for public key certificate. +// * +// * @param certificate certificate instance +// * @return updated builder instance +// */ +// public Builder publicKeyCert(X509Certificate certificate) { +// this.explicitPublicCert = certificate; +// return this; +// } +// +// /** +// * Add an X.509 certificate instance to the end of certification chain. +// * +// * @param certificate certificate to add to certification path +// * @return updated builder instance +// */ +// public Builder addCertChain(X509Certificate certificate) { +// this.explicitCertChain.add(certificate); +// return this; +// } +// +// /** +// * Add a certificate to the list of certificates, used e.g. in a trust store. +// * +// * @param certificate X.509 certificate to trust +// * @return updated builder instance +// */ +// public Builder addCert(X509Certificate certificate) { +// this.explicitCertificates.add(certificate); +// return this; +// } +// +// /** +// * Update this builder with information from a pem builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#pemBuilder()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "pem") +// public Builder updateWith(PemBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Update this builder with information from a keystore builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#keystoreBuilder()} ()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "keystore") +// public Builder updateWith(KeystoreBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Updated this builder instance from configuration. +// * Keys configured will override existing fields in this builder, others will be left intact. +// * If certification path is already defined, configuration based cert-path will be added. +// * +// * @param config configuration to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// updateWith(pemBuilder().config(config)); +// updateWith(keystoreBuilder().config(config)); +// +// return this; +// } +// } +// +// /** +// * Builder for resources from a java keystore (PKCS12, JKS etc.). Obtain an instance through {@link +// * FakeKeyConfigBean#keystoreBuilder()}. +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class KeystoreBuilder implements io.helidon.common.Builder { +// private static final String DEFAULT_KEYSTORE_TYPE = "PKCS12"; +// +// private String keystoreType = DEFAULT_KEYSTORE_TYPE; +// private char[] keystorePassphrase = EMPTY_CHARS; +// private char[] keyPassphrase = null; +// private String keyAlias; +// private String certAlias; +// private String certChainAlias; +// private boolean addAllCertificates; +// private final List certificateAliases = new LinkedList<>(); +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); +// +// private KeystoreBuilder() { +// } +// +// /** +// * If you want to build a trust store, call this method to add all +// * certificates present in the keystore to certificate list. +// * +// * @return updated builder instance +// */ +// @ConfiguredOption(type = Boolean.class, value = "false") +// public KeystoreBuilder trustStore() { +// return trustStore(true); +// } +// +// private KeystoreBuilder trustStore(boolean isTrustStore) { +// this.addAllCertificates = isTrustStore; +// return this; +// } +// +// /** +// * Add an alias to list of aliases used to generate a trusted set of certificates. +// * +// * @param alias alias of a certificate +// * @return updated builder instance +// */ +// public KeystoreBuilder addCertAlias(String alias) { +// certificateAliases.add(alias); +// return this; +// } +// +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// +// /** +// * Set type of keystore. +// * Defaults to "PKCS12", expected are other keystore types supported by java then can store keys under aliases. +// * +// * @param keystoreType keystore type to load the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "type", value = "PKCS12") +// public KeystoreBuilder keystoreType(String keystoreType) { +// this.keystoreType = keystoreType; +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassphrase keystore pass-phrase +// * @return updated builder instance +// */ +// public KeystoreBuilder keystorePassphrase(char[] keystorePassphrase) { +// this.keystorePassphrase = Arrays.copyOf(keystorePassphrase, keystorePassphrase.length); +// +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassword keystore password to use, calls {@link #keystorePassphrase(char[])} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "passphrase") +// public KeystoreBuilder keystorePassphrase(String keystorePassword) { +// return keystorePassphrase(keystorePassword.toCharArray()); +// } +// +// /** +// * Alias of the private key in the keystore. +// * +// * @param keyAlias alias of the key in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.alias", value = "1") +// public KeystoreBuilder keyAlias(String keyAlias) { +// this.keyAlias = keyAlias; +// return this; +// } +// +// /** +// * Alias of X.509 certificate of public key. +// * Used to load both the certificate and public key. +// * +// * @param alias alias under which the certificate is stored in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert.alias") +// public KeystoreBuilder certAlias(String alias) { +// this.certAlias = alias; +// return this; +// } +// +// /** +// * Alias of an X.509 chain. +// * +// * @param alias alias of certificate chain in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.alias") +// public KeystoreBuilder certChainAlias(String alias) { +// this.certChainAlias = alias; +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// public KeystoreBuilder keyPassphrase(char[] privateKeyPassphrase) { +// this.keyPassphrase = Arrays.copyOf(privateKeyPassphrase, privateKeyPassphrase.length); +// +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public KeystoreBuilder keyPassphrase(String privateKeyPassphrase) { +// return keyPassphrase(privateKeyPassphrase.toCharArray()); +// } +// +// /** +// * Create an instance of {@link FakeKeyConfigBean} based on this builder. +// * +// * @return new key config based on a keystore +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Create a builder for {@link FakeKeyConfigBean} from this keystore builder. This allows you to enhance the config +// * with additional (explicit) fields. +// * +// * @return builder of {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// + +// private Builder updateBuilder(Builder builder) { +// if (keystoreStream.isSet()) { +// if (null == keyPassphrase) { +// keyPassphrase = keystorePassphrase; +// } +// KeyStore keyStore; +// +// try { +// keyStore = PkiUtil.loadKeystore(keystoreType, +// keystoreStream.stream(), +// keystorePassphrase, +// keystoreStream.message()); +// } finally { +// keystoreStream.closeStream(); +// } +// +// // attempt to read private key +// boolean guessing = false; +// if (null == keyAlias) { +// keyAlias = DEFAULT_PRIVATE_KEY_ALIAS; +// guessing = true; +// } +// try { +// builder.privateKey(PkiUtil.loadPrivateKey(keyStore, keyAlias, keyPassphrase)); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to read private key from default alias", e); +// } else { +// throw e; +// } +// } +// +// List certChain = null; +// if (null == certChainAlias) { +// guessing = true; +// // by default, cert chain uses the same alias as private key +// certChainAlias = keyAlias; +// } else { +// guessing = false; +// } +// +// if (null != certChainAlias) { +// try { +// certChain = PkiUtil.loadCertChain(keyStore, certChainAlias); +// certChain.forEach(builder::addCertChain); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to certificate chain from alias \"" + certChainAlias + "\"", e); +// } else { +// throw e; +// } +// } +// } +// +// if (null == certAlias) { +// // no explicit public key certificate, just load it from cert chain if present +// if (null != certChain && !certChain.isEmpty()) { +// builder.publicKeyCert(certChain.get(0)); +// } +// } else { +// builder.publicKeyCert(PkiUtil.loadCertificate(keyStore, certAlias)); +// } +// +// if (addAllCertificates) { +// PkiUtil.loadCertificates(keyStore).forEach(builder::addCert); +// } else { +// certificateAliases.forEach(it -> builder.addCert(PkiUtil.loadCertificate(keyStore, it))); +// } +// } +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } +// } +// + +// /** +// * Builder for PEM files - accepts private key and certificate chain. Obtain an instance through {@link +// * FakeKeyConfigBean#pemBuilder()}. +// * +// * If you have "standard" linux/unix private key, you must run " +// * {@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa.p8}" on it to work with this builder for password protected +// * file; or "{@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa_nocrypt.p8 -nocrypt}" for unprotected file. +// * +// * The only supported format is PKCS#8. If you have a different format, you must to transform it to PKCS8 PEM format (to +// * use this builder), or to PKCS#12 keystore format (and use {@link KeystoreBuilder}). +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class PemBuilder implements io.helidon.common.Builder { +// private final StreamHolder privateKeyStream = new StreamHolder("privateKey"); +// private final StreamHolder publicKeyStream = new StreamHolder("publicKey"); +// private final StreamHolder certChainStream = new StreamHolder("certChain"); +// private final StreamHolder certificateStream = new StreamHolder("certificate"); +// private char[] pemKeyPassphrase; +// +// private PemBuilder() { +// } +// +// /** +// * Read a private key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.resource") +// public PemBuilder key(Resource resource) { +// privateKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Read a public key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder publicKey(Resource resource) { +// publicKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// public PemBuilder keyPassphrase(char[] passphrase) { +// this.pemKeyPassphrase = Arrays.copyOf(passphrase, passphrase.length); +// +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public PemBuilder keyPassphrase(String passphrase) { +// return keyPassphrase(passphrase.toCharArray()); +// } +// +// /** +// * Load certificate chain from PEM resource. +// * +// * @param resource resource (e.g. classpath, file path, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.resource") +// public PemBuilder certChain(Resource resource) { +// certChainStream.stream(resource); +// return this; +// } +// +// /** +// * Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder certificates(Resource resource) { +// certificateStream.stream(resource); +// return this; +// } +// +// /** +// * Build {@link FakeKeyConfigBean} based on information from PEM files only. +// * +// * @return new instance configured from this builder +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Get a builder filled from this builder to add additional information (such as public key from certificate etc.). +// * +// * @return builder for {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// +// private Builder updateBuilder(Builder builder) { +// if (privateKeyStream.isSet()) { +// builder.privateKey(PemReader.readPrivateKey(privateKeyStream.stream(), pemKeyPassphrase)); +// } +// if (publicKeyStream.isSet()) { +// builder.publicKey(PemReader.readPublicKey(publicKeyStream.stream())); +// } +// +// if (certChainStream.isSet()) { +// List chain = PemReader.readCertificates(certChainStream.stream()); +// chain.forEach(builder::addCertChain); +// if (!chain.isEmpty()) { +// builder.publicKeyCert(chain.get(0)); +// } +// } +// +// if (certificateStream.isSet()) { +// PemReader.readCertificates(certificateStream.stream()).forEach(builder::addCert); +// } +// +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * Expected keys: +// *
    +// *
  • pem-key-path - path to PEM private key file (PKCS#8 format)
  • +// *
  • pem-key-resource-path - path to resource on classpath
  • +// *
  • pem-key-passphrase - passphrase of private key if encrypted
  • +// *
  • pem-cert-chain-path - path to certificate chain PEM file
  • +// *
  • pem-cert-chain-resource-path - path to resource on classpath
  • +// *
+// * +// * @param config configuration to update builder from +// * @return updated builder instance +// */ +// public PemBuilder config(Config config) { +// Config pemConfig = config.get("pem"); +// pemConfig.get("key.resource").as(Resource::create).ifPresent(this::key); +// pemConfig.get("key.passphrase").asString().map(String::toCharArray).ifPresent(this::keyPassphrase); +// pemConfig.get("cert-chain.resource").as(Resource::create).ifPresent(this::certChain); +// pemConfig.get("certificates.resource").as(Resource::create).ifPresent(this::certificates); +// return this; +// } +// } +// +// private static final class StreamHolder { +// private final String baseMessage; +// private InputStream inputStream; +// private String message; +// +// private StreamHolder(String message) { +// this.baseMessage = message; +// this.message = message; +// } +// +// private boolean isSet() { +// return inputStream != null; +// } +// +// private void stream(Resource resource) { +// closeStream(); +// Objects.requireNonNull(resource, "Resource for \"" + message + "\" must not be null"); +// +// this.inputStream = resource.stream(); +// this.message = message + ":" + resource.sourceType() + ":" + resource.location(); +// } +// +// private InputStream stream() { +// return inputStream; +// } +// +// private String message() { +// return message; +// } +// +// private void closeStream() { +// if (null != inputStream) { +// try { +// inputStream.close(); +// } catch (IOException e) { +// LOGGER.log(Level.WARNING, "Failed to close input stream: " + message, e); +// } +// } +// message = baseMessage; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java new file mode 100644 index 00000000000..563db6276a3 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java @@ -0,0 +1,132 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka KeyConfig.Keystore.Builder + */ +@ConfigBean +public interface FakeKeystoreConfig { + + String DEFAULT_KEYSTORE_TYPE = "PKCS12"; + +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); + +// default FakeKeystoreConfigBean trustStore() { +// return trustStore(true); +// } + + @ConfiguredOption(key = "trust-store") + boolean trustStore(); + +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// default DefaultFakeKeystoreConfigBean.Builder keystore(Resource keystore) { +// +// } + + @ConfiguredOption(key = "type", value = DEFAULT_KEYSTORE_TYPE) + String keystoreType(); + + @ConfiguredOption(key = "passphrase") + char[] keystorePassphrase(); + + @ConfiguredOption(key = "key.alias", value = "1") + String keyAlias(); + + @ConfiguredOption(key = "key.passphrase") + char[] keyPassphrase(); + + @ConfiguredOption(key = "cert.alias") + @Singular("certAlias") + List certAliases(); + + @ConfiguredOption(key = "cert-chain.alias") + String certChainAlias(); + + +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java new file mode 100644 index 00000000000..238f795421a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes.config; + +public enum FakeNettyClientAuth { + NONE, + OPTIONAL, + REQUIRE; + + private FakeNettyClientAuth() { + } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java new file mode 100644 index 00000000000..6a8f321ae6d --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java @@ -0,0 +1,179 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka PathTracing. + * + * Traced system configuration for web server for a specific path. + */ +@ConfigBean +public interface FakePathTracingConfig { +// /** +// * Create a new traced path configuration from {@link io.helidon.config.Config}. +// * @param config config of a path +// * @return traced path configuration +// */ +// static FakePathTracingConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * Create a new builder to configure traced path configuration. +// * +// * @return a new builder instance +// */ +// static Builder builder() { +// return new Builder(); +// } + + /** + * Path this configuration should configure. + * + * @return path on the web server + */ + String path(); + + /** + * Method(s) this configuration should be valid for. This can be used to restrict the configuration + * only to specific HTTP methods (such as {@code GET} or {@code POST}). + * + * @return list of methods, if empty, this configuration is valid for any method + */ + @Singular("method") // Builder::addMethod(String method); + List methods(); + +// /** +// * Associated configuration of tracing valid for the configured path and (possibly) methods. +// * +// * @return traced system configuration +// */ + @ConfiguredOption(required = true) + FakeTracingConfig tracedConfig(); + +// Optional tracedConfig(); + + +// /** +// * Fluent API builder for {@link FakePathTracingConfigBean}. +// */ +// final class Builder implements io.helidon.common.Builder { +// private final List methods = new LinkedList<>(); +// private String path; +// private TracingConfig tracedConfig; +// +// private Builder() { +// } +// +// @Override +// public FakePathTracingConfigBean build() { +// // immutable +// final String finalPath = path; +// final List finalMethods = new LinkedList<>(methods); +// final TracingConfig finalTracingConfig = tracedConfig; +// +// return new FakePathTracingConfigBean() { +// @Override +// public String path() { +// return finalPath; +// } +// +// @Override +// public List methods() { +// return finalMethods; +// } +// +// @Override +// public TracingConfig tracedConfig() { +// return finalTracingConfig; +// } +// +// @Override +// public String toString() { +// return path + "(" + finalMethods + "): " + finalTracingConfig; +// } +// }; +// } +// +// /** +// * Update this builder from provided {@link io.helidon.config.Config}. +// * +// * @param config config to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// path(config.get("path").asString().get()); +// List methods = config.get("methods").asList(String.class).orElse(null); +// if (null != methods) { +// methods(methods); +// } +// tracingConfig(TracingConfig.create(config)); +// +// return this; +// } +// +// /** +// * Path to register the traced configuration on. +// * +// * @param path path as understood by {@link io.helidon.webserver.Routing.Builder} of web server +// * @return updated builder instance +// */ +// public Builder path(String path) { +// this.path = path; +// return this; +// } +// +// /** +// * HTTP methods to restrict registration of this configuration on web server. +// * @param methods list of methods to use, empty means all methods +// * @return updated builder instance +// */ +// public Builder methods(List methods) { +// this.methods.clear(); +// this.methods.addAll(methods); +// return this; +// } +// +// /** +// * Add a new HTTP method to restrict this configuration for. +// * +// * @param method method to add to the list of supported methods +// * @return updated builder instance +// */ +// public Builder addMethod(String method) { +// this.methods.add(method); +// return this; +// } +// +// /** +// * Configuration of a traced system to use on this path and possibly method(s). +// * +// * @param tracedConfig configuration of components, spans and span logs +// * @return updated builder instance +// */ +// public Builder tracingConfig(TracingConfig tracedConfig) { +// this.tracedConfig = tracedConfig; +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java new file mode 100644 index 00000000000..502b41fdec1 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java @@ -0,0 +1,699 @@ +/* + * 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.pico.builder.config.fakes.config; + +/* + * 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. + */ + +/** + * aka Routing. + * + * an annotation to get something discovered (i.e., @CustomConfigBean?) + * + * Routing represents composition of HTTP request-response handlers with routing rules. + * It is a cornerstone of the {@link io.helidon.pico.config.fake.helidon.WebServer}. + */ +public interface FakeRoutingConfig extends FakeServerLifecycle { + +// void route(BareRequest bareRequest, BareResponse bareResponse); +// +// /** +// * Creates new instance of {@link Builder routing builder}. +// * +// * @return a new instance +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * An API to define HTTP request routing rules. +// * +// * @see Builder +// */ +// interface Rules { +// /** +// * Configuration of tracing for this routing. +// * The configuration may control whether to log specific components, +// * spans and span logs, either globally, or for a specific path and method combinations. +// * +// * @param webTracingConfig WebServer tracing configuration +// * @return Updated routing configuration +// */ +// Rules register(WebTracingConfig webTracingConfig); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return Updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(Supplier... serviceBuilders); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(String pathPattern, Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return an updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(String pathPattern, Supplier... serviceBuilders); +// +// /** +// * Routes all GET requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(Handler... requestHandlers); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(String pathPattern, Handler... requestHandlers); +// +// /** +// * Add a route. This allows also protocol version specific routing. +// * +// * @param route route to add +// * @return updated rules +// */ +// Rules route(HttpRoute route); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all PUT requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for a registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all POST requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all RFC 5789 PATCH requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all DELETE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all OPTIONS requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all HEAD requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all TRACE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes requests any specified method to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Registers callback on created new {@link WebServer} instance with this routing. +// * +// * @param webServerConsumer a WebServer creation callback +// * @return updated routing configuration +// */ +// Rules onNewWebServer(Consumer webServerConsumer); +// } +// +// /** +// * A {@link Routing} builder. +// */ +// class Builder implements Rules, io.helidon.common.Builder { +// +// private final RouteListRoutingRules delegate = new RouteListRoutingRules(); +// private final List> errorHandlerRecords = new ArrayList<>(); +// private boolean tracingRegistered; +// +// /** +// * Creates new instance. +// */ +// private Builder() { +// } +// +// // --------------- ROUTING API +// +// @Override +// public Builder register(WebTracingConfig webTracingConfig) { +// this.tracingRegistered = true; +// delegate.register(webTracingConfig); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(Supplier... serviceBuilders) { +// delegate.register(serviceBuilders); +// return this; +// } +// +// @Override +// public Builder register(Service... services) { +// delegate.register(services); +// return this; +// } +// +// @Override +// public Builder register(String pathPattern, Service... services) { +// delegate.register(pathPattern, services); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(String pathPattern, Supplier... serviceBuilders) { +// delegate.register(pathPattern, serviceBuilders); +// return this; +// } +// +// @Override +// public Builder get(Handler... requestHandlers) { +// delegate.get(requestHandlers); +// return this; +// } +// +// @Override +// public Builder get(String pathPattern, Handler... requestHandlers) { +// delegate.get(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder route(HttpRoute route) { +// delegate.register(route); +// return this; +// } +// +// @Override +// public Builder get(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.get(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(Handler... requestHandlers) { +// delegate.put(requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(String pathPattern, Handler... requestHandlers) { +// delegate.put(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.put(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(Handler... requestHandlers) { +// delegate.post(requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(String pathPattern, Handler... requestHandlers) { +// delegate.post(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.post(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(Handler... requestHandlers) { +// delegate.patch(requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(String pathPattern, Handler... requestHandlers) { +// delegate.patch(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.patch(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(Handler... requestHandlers) { +// delegate.delete(requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(String pathPattern, Handler... requestHandlers) { +// delegate.delete(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.delete(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(Handler... requestHandlers) { +// delegate.options(requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(String pathPattern, Handler... requestHandlers) { +// delegate.options(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.options(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(Handler... requestHandlers) { +// delegate.head(requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(String pathPattern, Handler... requestHandlers) { +// delegate.head(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.head(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(Handler... requestHandlers) { +// delegate.trace(requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(String pathPattern, Handler... requestHandlers) { +// delegate.trace(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.trace(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(Handler... requestHandlers) { +// delegate.any(requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(String pathPattern, Handler... requestHandlers) { +// delegate.any(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.any(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, Handler... requestHandlers) { +// delegate.anyOf(methods, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, String pathPattern, Handler... requestHandlers) { +// delegate.anyOf(methods, pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, +// PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.anyOf(methods, pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder onNewWebServer(Consumer webServerConsumer) { +// delegate.onNewWebServer(webServerConsumer); +// return this; +// } +// // --------------- ERROR API +// +// /** +// * Registers an error handler that handles the given type of exceptions. +// * +// * @param exceptionClass the type of exception to handle by this handler +// * @param errorHandler the error handler +// * @param an error handler type +// * @return an updated builder +// */ +// public Builder error(Class exceptionClass, ErrorHandler errorHandler) { +// if (errorHandler == null) { +// return this; +// } +// errorHandlerRecords.add(RequestRouting.ErrorHandlerRecord.of(exceptionClass, errorHandler)); +// +// return this; +// } +// +// // --------------- BUILD API +// +// /** +// * Builds a new routing instance. +// * +// * @return a new instance +// */ +// public Routing build() { +// if (!tracingRegistered) { +// register(WebTracingConfig.create()); +// } +// RouteListRoutingRules.Aggregation aggregate = delegate.aggregate(); +// return new RequestRouting(aggregate.routeList(), errorHandlerRecords, aggregate.newWebServerCallbacks()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java new file mode 100644 index 00000000000..e5b1f3f4a61 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java @@ -0,0 +1,763 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ServerConfiguration. + */ +@ConfigBean +public interface FakeServerConfig extends FakeSocketConfig { + + /** + * Returns the count of threads in the pool used to process HTTP requests. + *

+ * Default value is {@link Runtime#availableProcessors()}. + * + * @return a workers count + */ + int workersCount(); + + /** + * Returns a server port to listen on with the default server socket. If port is + * {@code 0} then any available ephemeral port will be used. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return the server port of the default server socket + */ + @Override + int port(); + +// /** +// * Returns local address where the server listens on with the default server socket. +// * If {@code null} then listens an all local addresses. +// *

+// * Additional named server socket configuration is accessible through +// * the {@link #socket(String)} and {@link #sockets()} methods. +// * +// * @return an address to bind with the default server socket; {@code null} for all local addresses +// */ +// @Override +// InetAddress bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the default server + * socket. + *

+ * Default value is {@link FakeSocketConfig#DEFAULT_BACKLOG_SIZE}. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a maximum length of the queue of incoming connections + */ + @Override + int backlog(); + + /** + * Returns a default server socket timeout in milliseconds or {@code 0} for an infinite timeout. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a default server socket timeout in milliseconds or {@code 0} + */ + @Override + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * default server socket. + *

+ * If {@code 0} then use implementation default. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a buffer size in bytes of the default server socket or {@code 0} + */ + @Override + int receiveBufferSize(); + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code null} if there is no such + * named server socket + * @deprecated since 2.0.0, please use {@link #namedSocket(String)} instead + */ + @Deprecated + default FakeSocketConfig socket(String name) { + return namedSocket(name).orElse(null); + } + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code empty} if there is no such + * named server socket configured + */ + default Optional namedSocket(String name) { + return Optional.ofNullable(sockets().get(name)); + } + + /** + * A map of all the configured server sockets; that is the default server socket + * which is identified by the key {@link io.helidon.pico.config.fake.helidon.WebServer#DEFAULT_SOCKET_NAME} and also all the additional + * named server socket configurations. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @return a map of all the configured server sockets, never null + */ + @Singular("socket") + Map sockets(); + + /** + * The maximum amount of time that the server will wait to shut + * down regardless of the value of any additionally requested + * quiet period. + * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(10L)}.

+ * + * @return the {@link java.time.Duration} to use + */ +// TODO: @DefaultValue (Duration translation) + @ConfiguredOption(key = "whatever") + default Duration maxShutdownTimeout() { + return Duration.ofSeconds(10L); + } + + /** + * The quiet period during which the webserver will wait for new + * incoming connections after it has been told to shut down. + * + *

The webserver will wait no longer than the duration returned + * by the {@link #maxShutdownTimeout()} method.

+ * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(0L)}, indicating + * that there will be no quiet period.

+ * + * @return the {@link java.time.Duration} to use + */ + default Duration shutdownQuietPeriod() { + return Duration.ofSeconds(0L); + } + +// /** +// * Returns a Tracer. +// * +// * @return a tracer to use - never {@code null} +// */ +// Tracer tracer(); + +// /** +// * The top level {@link io.helidon.common.context.Context} to be used by this webserver. +// * @return a context instance with registered application scoped instances +// */ +// Context context(); +// +// /** +// * Returns an optional {@link Transport}. +// * +// * @return an optional {@link Transport} +// */ +// default Optional transport() { +// return Optional.ofNullable(null); +// } + + /** + * Whether to print details of HelidonFeatures. + * + * @return whether to print details + */ + boolean printFeatureDetails(); + +// /** +// * Creates new instance with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new instance +// */ +// static FakeServerConfigBean create(Config config) { +// return builder(config).build(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder}. +// * +// * @return a new builder instance +// * +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()} instead +// */ +// @Deprecated +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder} with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new builder instance +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()}, then +// * {@link WebServer.Builder#config(io.helidon.config.Config)}, or +// * {@link io.helidon.webserver.WebServer#create(Routing, io.helidon.config.Config)} +// */ +// @Deprecated +// static Builder builder(Config config) { +// return new Builder().config(config); +// } +// +// /** +// * A {@link FakeServerConfigBean} builder. +// * +// * @deprecated since 2.0.0 - use {@link io.helidon.webserver.WebServer.Builder} instead +// */ +// @Deprecated +// final class Builder implements FakeSocketConfigBean.SocketConfigurationBuilder, +// io.helidon.common.Builder { +// +// private static final AtomicInteger WEBSERVER_COUNTER = new AtomicInteger(1); +// private final Map socketBuilders = new HashMap<>(); +// private final Map socketsConfigs = new HashMap<>(); +// private int workers; +// private Tracer tracer; +// private Duration maxShutdownTimeout; +// private Duration shutdownQuietPeriod; +// private Optional transport; +// private Context context; +// private boolean printFeatureDetails; +// +// private Builder() { +// transport = Optional.ofNullable(null); +// maxShutdownTimeout = Duration.ofSeconds(10L); +// shutdownQuietPeriod = Duration.ofSeconds(0L); +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContext ssl context +// * @return an updated builder +// */ +// public Builder ssl(SSLContext sslContext) { +// defaultSocketBuilder().ssl(sslContext); +// return this; +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContextBuilder ssl context builder; will be built as a first step of this method execution +// * @return an updated builder +// */ +// public Builder ssl(Supplier sslContextBuilder) { +// defaultSocketBuilder().ssl(sslContextBuilder); +// return this; +// } +// +// /** +// * Sets server port. If port is {@code 0} or less then any available ephemeral port will be used. +// *

+// * Configuration key: {@code port} +// * +// * @param port the server port +// * @return an updated builder +// */ +// public Builder port(int port) { +// defaultSocketBuilder().port(port); +// return this; +// } +// +// /** +// * Sets a local address for server to bind. If {@code null} then listens an all local addresses. +// *

+// * Configuration key: {@code bind-address} +// * +// * @param bindAddress the address to bind the server or {@code null} for all local addresses +// * @return an updated builder +// */ +// public Builder bindAddress(InetAddress bindAddress) { +// defaultSocketBuilder().bindAddress(bindAddress); +// return this; +// } +// +// /** +// * Sets a maximum length of the queue of incoming connections. Default value is {@code 1024}. +// *

+// * Configuration key: {@code backlog} +// * +// * @param size the maximum length of the queue of incoming connections +// * @return an updated builder +// */ +// public Builder backlog(int size) { +// defaultSocketBuilder().backlog(size); +// return this; +// } +// +// /** +// * Sets a socket timeout in milliseconds or {@code 0} for infinite timeout. +// *

+// * Configuration key: {@code timeout} +// * +// * @param milliseconds a socket timeout in milliseconds or {@code 0} +// * @return an updated builder +// */ +// public Builder timeout(int milliseconds) { +// defaultSocketBuilder().timeoutMillis(milliseconds); +// return this; +// } +// +// /** +// * Propose value of the TCP receive window that is advertised to the remote peer. +// * If {@code 0} then implementation default is used. +// *

+// * Configuration key: {@code receive-buffer} +// * +// * @param bytes a buffer size in bytes or {@code 0} +// * @return an updated builder +// */ +// public Builder receiveBufferSize(int bytes) { +// defaultSocketBuilder().receiveBufferSize(bytes); +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// defaultSocketBuilder().maxHeaderSize(size); +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// defaultSocketBuilder().maxInitialLineLength(length); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param port the port to bind; if {@code 0} or less, any available ephemeral port will be used +// * @param bindAddress the address to bind; if {@code null}, all local addresses will be bound +// * @return an updated builder +// * +// * @deprecated since 2.0.0, please use {@link #addSocket(String, FakeSocketConfigBean)} instead +// */ +// @Deprecated +// public Builder addSocket(String name, int port, InetAddress bindAddress) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// return addSocket(name, FakeSocketConfigBean.builder() +// .port(port) +// .bindAddress(bindAddress)); +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketsConfigs.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration builder +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean.Builder socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketBuilders.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration builder. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as +// * a first step of this method execution +// * @return an updated builder +// */ +// public Builder addSocket(String name, Supplier socketConfigurationBuilder) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// +// return addSocket(name, socketConfigurationBuilder != null ? socketConfigurationBuilder.get() : null); +// } +// +// /** +// * Sets a count of threads in pool used to process HTTP requests. +// * Default value is {@code CPU_COUNT * 2}. +// *

+// * Configuration key: {@code workers} +// * +// * @param workers a workers count +// * @return an updated builder +// */ +// public Builder workersCount(int workers) { +// this.workers = workers; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracer a tracer to set +// * @return an updated builder +// */ +// public Builder tracer(Tracer tracer) { +// this.tracer = tracer; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution +// * @return updated builder +// */ +// public Builder tracer(Supplier tracerBuilder) { +// return tracer(tracerBuilder.get()); +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(String... protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(List protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configure maximum client payload size. +// * @param size maximum payload size +// * @return an updated builder +// */ +// @Override +// public Builder maxPayloadSize(long size) { +// defaultSocketBuilder().maxPayloadSize(size); +// return this; +// } +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @Override +// public Builder maxUpgradeContentLength(int size) { +// defaultSocketBuilder().maxUpgradeContentLength(size); +// return this; +// } +// +// /** +// * Configure the maximum amount of time that the server will wait to shut +// * down regardless of the value of any additionally requested +// * quiet period. +// * @param maxShutdownTimeout the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder maxShutdownTimeout(Duration maxShutdownTimeout) { +// this.maxShutdownTimeout = +// Objects.requireNonNull(maxShutdownTimeout, "Parameter 'maxShutdownTimeout' must not be null!"); +// return this; +// } +// +// /** +// * Configure the quiet period during which the webserver will wait for new +// * incoming connections after it has been told to shut down. +// * @param shutdownQuietPeriod the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder shutdownQuietPeriod(Duration shutdownQuietPeriod) { +// this.shutdownQuietPeriod = +// Objects.requireNonNull(shutdownQuietPeriod, "Parameter 'shutdownQuietPeriod' must not be null!"); +// return this; +// } +// +// /** +// * Configure transport. +// * @param transport a {@link Transport} +// * @return an updated builder +// */ +// public Builder transport(Transport transport) { +// this.transport = Optional.of(transport); +// return this; +// } +// +// /** +// * Set to {@code true} to print detailed feature information on startup. +// * +// * @param print whether to print details or not +// * @return updated builder instance +// * @see io.helidon.common.HelidonFeatures +// */ +// public Builder printFeatureDetails(boolean print) { +// this.printFeatureDetails = print; +// return this; +// } +// +// /** +// * Configure the application scoped context to be used as a parent for webserver request contexts. +// * @param context top level context +// * @return an updated builder +// */ +// public Builder context(Context context) { +// this.context = context; +// +// return this; +// } +// +// private InetAddress string2InetAddress(String address) { +// try { +// return InetAddress.getByName(address); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * Sets configuration values included in provided {@link Config} parameter. +// *

+// * It can be used for configuration externalisation. +// *

+// * All parameters sets before this method call can be seen as defaults and all parameters sets after can be seen +// * as forced. +// * +// * @param config the configuration to use +// * @return an updated builder +// */ +// public Builder config(Config config) { +// if (config == null) { +// return this; +// } +// +// defaultSocketBuilder().config(config); +// +// config.get("host").asString().ifPresent(defaultSocketBuilder()::host); +// +// DeprecatedConfig.get(config, "worker-count", "workers") +// .asInt() +// .ifPresent(this::workersCount); +// +// config.get("features.print-details").asBoolean().ifPresent(this::printFeatureDetails); +// +// // shutdown timeouts +// config.get("max-shutdown-timeout-seconds").asLong().ifPresent(it -> maxShutdownTimeout(Duration.ofSeconds(it))); +// config.get("shutdown-quiet-period-seconds").asLong().ifPresent(it -> shutdownQuietPeriod(Duration.ofSeconds(it))); +// +// // sockets +// Config socketsConfig = config.get("sockets"); +// if (socketsConfig.exists()) { +// List socketConfigs = socketsConfig.asNodeList().orElse(List.of()); +// for (Config socketConfig : socketConfigs) { +// // the whole section checking the socket name can be removed +// // when we remove deprecated methods with socket name on server builder +// String socketName; +// +// String nodeName = socketConfig.name(); +// Optional maybeSocketName = socketConfig.get("name").asString().asOptional(); +// +// socketName = maybeSocketName.orElse(nodeName); +// +// // log warning for deprecated config +// try { +// Integer.parseInt(nodeName); +// if (socketName.equals(nodeName) && maybeSocketName.isEmpty()) { +// throw new ConfigException("Cannot find \"name\" key for socket configuration " + socketConfig.key()); +// } +// } catch (NumberFormatException e) { +// // this is old approach +// Logger.getLogger(SocketConfigurationBuilder.class.getName()) +// .warning("Socket configuration at " + socketConfig.key() + " is deprecated. Please use an array " +// + "with \"name\" key to define the socket name."); +// } +// +// FakeSocketConfigBean.Builder socket = FakeSocketConfigBean.builder() +// .name(socketName) +// .config(socketConfig); +// +// socketBuilders.put(socket.name(), socket); +// } +// } +// +// return this; +// } +// +// /** +// * Builds a new configuration instance. +// * +// * @return a new instance +// */ +// @Override +// public FakeServerConfigBean build() { +// if (null == context) { +// // I do not expect "unlimited" number of webservers +// // in case somebody spins a huge number up, the counter will cycle to negative numbers once +// // Integer.MAX_VALUE is reached. +// context = Context.builder() +// .id("web-" + WEBSERVER_COUNTER.getAndIncrement()) +// .build(); +// } +// +// Optional maybeTracer = context.get(Tracer.class); +// +// if (null == this.tracer) { +// this.tracer = maybeTracer.orElseGet(Tracer::global); +// } +// +// if (maybeTracer.isEmpty()) { +// context.register(this.tracer); +// } +// +// if (workers <= 0) { +// workers = Runtime.getRuntime().availableProcessors(); +// } +// +// return new ServerBasicConfig(this); +// } +// +// FakeSocketConfigBean.Builder defaultSocketBuilder() { +// return socketBuilder(WebServer.DEFAULT_SOCKET_NAME); +// } +// +// FakeSocketConfigBean.Builder socketBuilder(String socketName) { +// return socketBuilders.computeIfAbsent(socketName, k -> FakeSocketConfigBean.builder().name(socketName)); +// } +// +// Map sockets() { +// Set builtSocketConfigsKeys = socketsConfigs.keySet(); +// Map result = +// new HashMap<>(this.socketBuilders.size() + this.socketsConfigs.size()); +// for (Map.Entry e : this.socketBuilders.entrySet()) { +// String key = e.getKey(); +// if (builtSocketConfigsKeys.contains(key)) { +// throw new IllegalStateException("Both mutable and immutable socket configuration provided for named socket " +// + key); +// } +// result.put(key, e.getValue().build()); +// } +// +// result.putAll(this.socketsConfigs); +// return result; +// } +// +// int workers() { +// return workers; +// } +// +// Tracer tracer() { +// return tracer; +// } +// +// Duration maxShutdownTimeout() { +// return maxShutdownTimeout; +// } +// +// Duration shutdownQuietPeriod() { +// return shutdownQuietPeriod; +// } +// +// Optional transport() { +// return transport; +// } +// +// Context context() { +// return context; +// } +// +// boolean printFeatureDetails() { +// return printFeatureDetails; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// defaultSocketBuilder().timeout(amount, unit); +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// defaultSocketBuilder().tls(webServerTls); +// return this; +// } +// +// @Override +// public Builder enableCompression(boolean value) { +// defaultSocketBuilder().enableCompression(value); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java new file mode 100644 index 00000000000..49dd3296f63 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java @@ -0,0 +1,38 @@ +/* + * 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.pico.builder.config.fakes.config; + +/** + * aka ServerLifecycle. + * + * Basic server lifecycle operations. + */ +public interface FakeServerLifecycle { + +// /** +// * Before server start. +// */ +// default void beforeStart() { +// } +// +// /** +// * After server stop. +// */ +// default void afterStop() { +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java new file mode 100644 index 00000000000..6adf615a31b --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java @@ -0,0 +1,849 @@ +/* + * 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.pico.builder.config.fakes.config; + +/* + * 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 java.util.Optional; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.fakes.WebServer; + +/** + * aka ServerConfiguration. + * + * The SocketConfiguration configures a port to listen on and its associated server socket parameters. + */ +@ConfigBean +public interface FakeSocketConfig { + + /** + * The default backlog size to configure the server sockets with if no other value + * is provided. + */ + int DEFAULT_BACKLOG_SIZE = 1024; + + /** + * Name of this socket. + * Default to WebServer#DEFAULT_SOCKET_NAME for the main and + * default server socket. All other sockets must be named. + * + * @return name of this socket + */ +// default String name() { +// return WebServer.DEFAULT_SOCKET_NAME; +// } + @ConfiguredOption(WebServer.DEFAULT_SOCKET_NAME) + String name(); + + /** + * Returns a server port to listen on with the server socket. If port is + * {@code 0} then any available ephemeral port will be used. + * + * @return the server port of the server socket + */ + int port(); + +// /** +// * Returns local address where the server listens on with the server socket. +// * If {@code null} then listens an all local addresses. +// * +// * @return an address to bind with the server socket; {@code null} for all local addresses +// */ +// InetAddress bindAddress(); + @ConfiguredOption(key = "bind-address") + String bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the server + * socket. + *

+ * Default value is {@link #DEFAULT_BACKLOG_SIZE}. + * + * @return a maximum length of the queue of incoming connections + */ + @ConfiguredOption("1024") + int backlog(); + + /** + * Returns a server socket timeout in milliseconds or {@code 0} for an infinite timeout. + * + * @return a server socket timeout in milliseconds or {@code 0} + */ + @ConfiguredOption(key = "timeout-millis") + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * server socket. + *

+ * If {@code 0} then use implementation default. + * + * @return a buffer size in bytes of the server socket or {@code 0} + */ + int receiveBufferSize(); + + /** + * Return a {@link FakeWebServerTlsConfig} containing server TLS configuration. When empty {@link java.util.Optional} is returned + * no TLS should be configured. + * + * @return web server tls configuration + */ + Optional tls(); + + /** + * Returns a {@link javax.net.ssl.SSLContext} to use with the server socket. If not {@code null} then + * the server enforces an SSL communication. + * + * @deprecated use {@code tls().sslContext()} instead. This method will be removed at 3.0.0 version. + * @return a SSL context to use + */ + @Deprecated(since = "2.3.1", forRemoval = true) + SSLContext ssl(); + + /** + * Returns the SSL protocols to enable, or {@code null} to enable the default + * protocols. + * @deprecated use {@code tls().enabledTlsProtocols()} instead. This method will be removed at 3.0.0 version. + * @return the SSL protocols to enable + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set enabledSslProtocols(); + + /** + * Return the allowed cipher suite of the TLS. If empty set is returned, the default cipher suite is used. + * + * @deprecated use {@code tls().cipherSuite()} instead. This method will be removed at 3.0.0 version. + * @return the allowed cipher suite + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set allowedCipherSuite(); + + /** + * Whether to require client authentication or not. + * + * @deprecated use {@code tls().clientAuth()} instead. This method will be removed at 3.0.0 version. + * @return client authentication + */ + @Deprecated(since = "2.3.1", forRemoval = true) + FakeNettyClientAuth clientAuth(); + + /** + * Whether this socket is enabled (and will be opened on server startup), or disabled + * (and ignored on server startup). + * + * @return {@code true} for enabled socket, {@code false} for socket that should not be opened + */ +// default boolean enabled() { +// return true; +// } + @ConfiguredOption("true") + boolean enabled(); + + /** + * Maximal size of all headers combined. + * + * @return size in bytes + */ + // TODO: should we automatically translate camel-case to dashes? + @ConfiguredOption(key = "max-header-size", value = "8192") + int maxHeaderSize(); + + /** + * Maximal length of the initial HTTP line. + * + * @return length + */ + @ConfiguredOption("4096") + int maxInitialLineLength(); + + /** + * Maximal size of a single chunk of received data. + * + * @return chunk size + */ + int maxChunkSize(); + + /** + * Whether to validate HTTP header names. + * When set to {@code true}, we make sure the header name is a valid string + * + * @return {@code true} if headers should be validated + */ + boolean validateHeaders(); + + /** + * Whether to allow negotiation for a gzip/deflate content encoding. Supporting + * HTTP compression may interfere with application that use streaming and other + * similar features. Thus, it defaults to {@code false}. + * + * @return compression flag + */ +// default boolean enableCompression() { +// return false; +// } + boolean enableCompression(); + + /** + * Maximum size allowed for an HTTP payload in a client request. A negative + * value indicates that there is no maximum set. + * + * @return maximum payload size + */ +// default long maxPayloadSize() { +// return -1L; +// } + @ConfiguredOption("-1") + long maxPayloadSize(); + + /** + * Initial size of the buffer used to parse HTTP line and headers. + * + * @return initial size of the buffer + */ + int initialBufferSize(); + + /** + * Maximum length of the content of an upgrade request. + * + * @return maximum length of the content of an upgrade request + */ +// default int maxUpgradeContentLength() { +// return 64 * 1024; +// } + @ConfiguredOption("65536") + int maxUpgradeContentLength(); + +// /** +// * Creates a builder of {@link FakeSocketConfigBean} class. +// * +// * @return a builder +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create a default named configuration. +// * +// * @param name name of the socket +// * @return a new socket configuration with defaults +// */ +// static FakeSocketConfigBean create(String name) { +// return builder() +// .name(name) +// .build(); +// } +// +// /** +// * Socket configuration builder API, used by {@link io.helidon.webserver.SocketConfiguration.Builder} +// * to configure additional sockets, and by {@link io.helidon.webserver.WebServer.Builder} to +// * configure the default socket. +// * +// * @param type of the subclass of this class to provide correct fluent API +// */ +// @Configured +// interface SocketConfigurationBuilder> { +// /** +// * Configures a server port to listen on with the server socket. If port is +// * {@code 0} then any available ephemeral port will be used. +// * +// * @param port the server port of the server socket +// * @return this builder +// */ +// @ConfiguredOption("0") +// B port(int port); +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param address an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// * @throws io.helidon.config.ConfigException in case the address provided is not a valid host address +// */ +// @ConfiguredOption(deprecated = true) +// default B bindAddress(String address) { +// try { +// return bindAddress(InetAddress.getByName(address)); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * A helper method that just calls {@link #bindAddress(String)}. +// * +// * @param address host to listen on +// * @return this builder +// */ +// @ConfiguredOption +// default B host(String address) { +// return bindAddress(address); +// } +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param bindAddress an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// */ +// B bindAddress(InetAddress bindAddress); +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// @ConfiguredOption("1024") +// B backlog(int backlog); +// +// /** +// * Configures a server socket timeout. +// * +// * @param amount an amount of time to configure the timeout, use {@code 0} for infinite timeout +// * @param unit time unit to use with the configured amount +// * @return this builder +// */ +// @ConfiguredOption(key = "timeout-millis", type = Long.class, value = "0", +// description = "Socket timeout in milliseconds") +// B timeout(long amount, TimeUnit unit); +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @ConfiguredOption +// B receiveBufferSize(int receiveBufferSize); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * If this method is called, any other method except for {@link #tls(java.util.function.Supplier)}¨ +// * and repeated invocation of this method would be ignored. +// *

+// * If this method is called again, the previous configuration would be ignored. +// * +// * @param webServerTls ssl configuration to use with this socket +// * @return this builder +// */ +// @ConfiguredOption +// B tls(FakeWebServerTlsConfigBean webServerTls); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * +// * @param tlsConfig supplier ssl configuration to use with this socket +// * @return this builder +// */ +// default B tls(Supplier tlsConfig) { +// return tls(tlsConfig.get()); +// } +// +// /** +// * Maximal number of bytes of all header values combined. When a bigger value is received, a +// * {@link io.helidon.common.http.Http.Status#BAD_REQUEST_400} +// * is returned. +// *

+// * Default is {@code 8192} +// * +// * @param size maximal number of bytes of combined header values +// * @return this builder +// */ +// @ConfiguredOption("8192") +// B maxHeaderSize(int size); +// +// /** +// * Maximal number of characters in the initial HTTP line. +// *

+// * Default is {@code 4096} +// * +// * @param length maximal number of characters +// * @return this builder +// */ +// @ConfiguredOption("4096") +// B maxInitialLineLength(int length); +// +// /** +// * Enable negotiation for gzip/deflate content encodings. Clients can +// * request compression using the "Accept-Encoding" header. +// *

+// * Default is {@code false} +// * +// * @param value compression flag +// * @return this builder +// */ +// @ConfiguredOption("false") +// B enableCompression(boolean value); +// +// /** +// * Set a maximum payload size for a client request. Can prevent DoS +// * attacks. +// * +// * @param size maximum payload size +// * @return this builder +// */ +// @ConfiguredOption +// B maxPayloadSize(long size); +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @ConfiguredOption("65536") +// B maxUpgradeContentLength(int size); +// +// /** +// * Update this socket configuration from a {@link io.helidon.config.Config}. +// * +// * @param config configuration on the node of a socket +// * @return updated builder instance +// */ +// @SuppressWarnings("unchecked") +// default B config(Config config) { +// config.get("port").asInt().ifPresent(this::port); +// config.get("bind-address").asString().ifPresent(this::host); +// config.get("backlog").asInt().ifPresent(this::backlog); +// config.get("max-header-size").asInt().ifPresent(this::maxHeaderSize); +// config.get("max-initial-line-length").asInt().ifPresent(this::maxInitialLineLength); +// config.get("max-payload-size").asInt().ifPresent(this::maxPayloadSize); +// +// DeprecatedConfig.get(config, "timeout-millis", "timeout") +// .asInt() +// .ifPresent(it -> this.timeout(it, TimeUnit.MILLISECONDS)); +// DeprecatedConfig.get(config, "receive-buffer-size", "receive-buffer") +// .asInt() +// .ifPresent(this::receiveBufferSize); +// +// Optional> enabledProtocols = DeprecatedConfig.get(config, "ssl.protocols", "ssl-protocols") +// .asList(String.class) +// .asOptional(); +// +// // tls +// Config sslConfig = DeprecatedConfig.get(config, "tls", "ssl"); +// if (sslConfig.exists()) { +// try { +// FakeWebServerTlsConfigBean.Builder builder = FakeWebServerTlsConfigBean.builder(); +// enabledProtocols.ifPresent(builder::enabledProtocols); +// builder.config(sslConfig); +// +// this.tls(builder.build()); +// } catch (IllegalStateException e) { +// throw new ConfigException("Cannot load SSL configuration.", e); +// } +// } +// +// // compression +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// return (B) this; +// } +// } +// +// /** +// * The {@link io.helidon.webserver.SocketConfiguration} builder class. +// */ +// @Configured +// final class Builder implements SocketConfigurationBuilder, io.helidon.common.Builder { +// /** +// * @deprecated remove once WebServer.Builder.addSocket(name, socket) methods are removed +// */ +// @Deprecated +// static final String UNCONFIGURED_NAME = "io.helidon.webserver.SocketConfiguration.UNCONFIGURED"; +// private final FakeWebServerTlsConfigBean.Builder tlsConfigBuilder = FakeWebServerTlsConfigBean.builder(); +// +// private int port = 0; +// private InetAddress bindAddress = null; +// private int backlog = DEFAULT_BACKLOG_SIZE; +// private int timeoutMillis = 0; +// private int receiveBufferSize = 0; +// private FakeWebServerTlsConfigBean webServerTls; +// // this is for backward compatibility, should be initialized to null once the +// // methods with `name` are removed from server builder (for adding sockets) +// private String name = UNCONFIGURED_NAME; +// private boolean enabled = true; +// // these values are as defined in Netty implementation +// private int maxHeaderSize = 8192; +// private int maxInitialLineLength = 4096; +// private int maxChunkSize = 8192; +// private boolean validateHeaders = true; +// private int initialBufferSize = 128; +// private boolean enableCompression = false; +// private long maxPayloadSize = -1; +// private int maxUpgradeContentLength = 64 * 1024; +// +// private Builder() { +// } +// +// @Override +// public FakeSocketConfigBean build() { +// if (null == webServerTls) { +// webServerTls = tlsConfigBuilder.build(); +// } +// +// if (null == name) { +// throw new ConfigException("Socket name must be configured for each socket"); +// } +// +// return new ServerBasicConfig.SocketConfig(this); +// } +// +// @Override +// public Builder port(int port) { +// this.port = port; +// return this; +// } +// +// @Override +// public Builder bindAddress(InetAddress bindAddress) { +// this.bindAddress = bindAddress; +// return this; +// } +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// public Builder backlog(int backlog) { +// this.backlog = backlog; +// return this; +// } +// +// /** +// * Configures a server socket timeout in milliseconds or {@code 0} for an infinite timeout. +// * +// * @param timeoutMillis a server socket timeout in milliseconds or {@code 0} +// * @return this builder +// * +// * @deprecated since 2.0.0 please use {@link #timeout(long, java.util.concurrent.TimeUnit)} instead +// */ +// @Deprecated +// public Builder timeoutMillis(int timeoutMillis) { +// this.timeoutMillis = timeoutMillis; +// return this; +// } +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @Override +// public Builder receiveBufferSize(int receiveBufferSize) { +// this.receiveBufferSize = receiveBufferSize; +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContext a SSL context to use +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link #tls(FakeWebServerTlsConfigBean)} instead +// */ +// @Deprecated +// public Builder ssl(SSLContext sslContext) { +// if (null != sslContext) { +// this.tlsConfigBuilder.sslContext(sslContext); +// } +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContextBuilder a SSL context builder to use; will be built as a first step of this +// * method execution +// * @return this builder +// * @deprecated since 2.0.0, please use {@link #tls(Supplier)} instead +// */ +// @Deprecated +// public Builder ssl(Supplier sslContextBuilder) { +// return ssl(sslContextBuilder != null ? sslContextBuilder.get() : null); +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link FakeWebServerTlsConfigBean.Builder#enabledProtocols(String...)} +// * instead +// */ +// @Deprecated +// public Builder enabledSSlProtocols(String... protocols) { +// if (null == protocols) { +// enabledSSlProtocols(List.of()); +// } else { +// enabledSSlProtocols(Arrays.asList(protocols)); +// } +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return this builder +// */ +// @Deprecated +// public Builder enabledSSlProtocols(List protocols) { +// if (null == protocols) { +// this.tlsConfigBuilder.enabledProtocols(List.of()); +// } else { +// this.tlsConfigBuilder.enabledProtocols(protocols); +// } +// return this; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// long timeout = unit.toMillis(amount); +// if (timeout > Integer.MAX_VALUE) { +// this.timeoutMillis = 0; +// } else { +// this.timeoutMillis = (int) timeout; +// } +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// this.webServerTls = webServerTls; +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// this.maxHeaderSize = size; +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// this.maxInitialLineLength = length; +// return this; +// } +// +// @Override +// public Builder maxPayloadSize(long size) { +// this.maxPayloadSize = size; +// return this; +// } +// +// @Override +// public Builder maxUpgradeContentLength(int size) { +// this.maxUpgradeContentLength = size; +// return this; +// } +// +// /** +// * Configure a socket name, to bind named routings to. +// * +// * @param name name of the socket +// * @return updated builder instance +// */ +// @ConfiguredOption(required = true) +// public Builder name(String name) { +// this.name = name; +// return this; +// } +// +// /** +// * Set this socket builder to enabled or disabled. +// * +// * @param enabled when set to {@code false}, the socket is not going to be opened by the server +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// return this; +// } +// +// /** +// * Configure maximal size of a chunk to be read from incoming requests. +// * Defaults to {@code 8192}. +// * +// * @param size maximal chunk size +// * @return updated builder instance +// */ +// public Builder maxChunkSize(int size) { +// this.maxChunkSize = size; +// return this; +// } +// +// /** +// * Configure whether to validate header names. +// * Defaults to {@code true} to make sure header names are valid strings. +// * +// * @param validate set to {@code false} to ignore header validation +// * @return updated builder instance +// */ +// public Builder validateHeaders(boolean validate) { +// this.validateHeaders = validate; +// return this; +// } +// +// /** +// * Configure initial size of the buffer used to parse HTTP line and headers. +// * Defaults to {@code 128}. +// * +// * @param size initial buffer size +// * @return updated builder instance +// */ +// public Builder initialBufferSize(int size) { +// this.initialBufferSize = size; +// return this; +// } +// +// /** +// * Configure whether to enable content negotiation for compression. +// * +// * @param value compression flag +// * @return updated builder instance +// */ +// public Builder enableCompression(boolean value) { +// this.enableCompression = value; +// return this; +// } +// +// @Override +// public Builder config(Config config) { +// SocketConfigurationBuilder.super.config(config); +// +// config.get("name").asString().ifPresent(this::name); +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("max-chunk-size").asInt().ifPresent(this::maxChunkSize); +// config.get("validate-headers").asBoolean().ifPresent(this::validateHeaders); +// config.get("initial-buffer-size").asInt().ifPresent(this::initialBufferSize); +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// +// return this; +// } +// +// int port() { +// return port; +// } +// +// Optional bindAddress() { +// return Optional.ofNullable(bindAddress); +// } +// +// int backlog() { +// return backlog; +// } +// +// int timeoutMillis() { +// return timeoutMillis; +// } +// +// int receiveBufferSize() { +// return receiveBufferSize; +// } +// +// FakeWebServerTlsConfigBean tlsConfig() { +// return webServerTls; +// } +// +// String name() { +// return name; +// } +// +// boolean enabled() { +// return enabled; +// } +// +// int maxHeaderSize() { +// return maxHeaderSize; +// } +// +// int maxInitialLineLength() { +// return maxInitialLineLength; +// } +// +// int maxChunkSize() { +// return maxChunkSize; +// } +// +// boolean validateHeaders() { +// return validateHeaders; +// } +// +// int initialBufferSize() { +// return initialBufferSize; +// } +// +// boolean enableCompression() { +// return enableCompression; +// } +// +// long maxPayloadSize() { +// return maxPayloadSize; +// } +// +// int maxUpgradeContentLength() { +// return maxUpgradeContentLength; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java new file mode 100644 index 00000000000..719ffc6b3e9 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java @@ -0,0 +1,128 @@ +/* + * 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.pico.builder.config.fakes.config; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanLogTracingConfig. + */ +@ConfigBean +public interface FakeSpanLogTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean DISABLED = FakeSpanLogTracingConfigBean.builder("disabled").enabled(false).build(); +// /** +// * Enabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean ENABLED = FakeSpanLogTracingConfigBean.builder("enabled").build(); +// +// /** +// * A new span log. +// * @param name name of the span log +// */ +// protected FakeSpanLogTracingConfigBean(String name) { +// super(name); +// } +// + +// /** +// * Merge two traced span log configurations. +// * +// * @param older original configuration with default values +// * @param newer new configuration to override the older +// * @return a new traced span log mergint the older and newer +// */ +// static FakeSpanLogTracingConfigBean merge(FakeSpanLogTracingConfigBean older, FakeSpanLogTracingConfigBean newer) { +// return new FakeSpanLogTracingConfigBean(newer.name()) { +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Fluent API builder to create a new traced span log configuration. +// * +// * @param name name of the span log +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced span log configuration from {@link io.helidon.config.Config}. +// * +// * @param name name of the span log +// * @param config config for a traced span log +// * @return a new traced span log configuration +// */ +// public static FakeSpanLogTracingConfigBean create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link FakeSpanLogTracingConfigBean}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final String name; +// private Optional enabled = Optional.empty(); +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public FakeSpanLogTracingConfigBean build() { +// final Optional finalEnabled = enabled; +// return new FakeSpanLogTracingConfigBean(name) { +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Configure whether this traced span log is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config config of a traced span log +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java new file mode 100644 index 00000000000..39a3e2a8130 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java @@ -0,0 +1,258 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Map; +import java.util.Optional; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanTracingConfig. + * + * Configuration of a single traced span. + */ +@ConfigBean +public interface FakeSpanTracingConfig extends FakeTraceableConfig { + +// /** +// * A traced span that is disabled and all logs on it are disabled as well. +// */ +// public static final SpanTracingConfig DISABLED = SpanTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * A traced span that is inabled and all logs on it are enabled as well. +// */ +// public static final SpanTracingConfig ENABLED = SpanTracingConfig.builder("enabled").build(); + +// /** +// * A new traceable span. +// * +// * @param name name of this span +// */ +// protected SpanTracingConfig(String name) { +// super(name); +// } +// +// @Override +// public String toString() { +// return "SpanTracingConfig(" + name() + ")"; +// } +// +// /** +// * Merge configuration of two traced spans. +// * +// * @param older older span with default values +// * @param newer newer span overriding values in older +// * @return a new merged traced span configuration +// */ +// static SpanTracingConfig merge(SpanTracingConfig older, SpanTracingConfig newer) { +// return new SpanTracingConfig(newer.name()) { +// @Override +// public Optional newName() { +// return newer.newName() +// .or(older::newName); +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// +// @Override +// public Optional getSpanLog(String name) { +// Optional newLog = newer.getSpanLog(name); +// Optional oldLog = older.getSpanLog(name); +// +// if (newLog.isPresent() && oldLog.isPresent()) { +// return Optional.of(SpanLogTracingConfig.merge(oldLog.get(), newLog.get())); +// } +// +// if (newLog.isPresent()) { +// return newLog; +// } +// +// return oldLog; +// } +// }; +// } + + /** + * When rename is desired, returns the new name. + * + * @return new name for this span or empty when rename is not desired + */ + Optional newName(); + +// /** +// * Configuration of a traced span log. +// * +// * @param name name of the log event +// * @return configuration of the log event, or empty if not explicitly configured (used when merging) +// */ +// protected abstract Optional getSpanLog(String name); + + @Singular("spanLog") // B addSpanLog(String, FakeSpanLogTracingConfigBean); + Map spanLogMap(); + +// /** +// * Configuration of a traceable span log. +// * If this span is disabled, the log is always disabled. +// * +// * @param name name of the log event +// * @return configuration of the log event +// */ +// public final SpanLogTracingConfig spanLog(String name) { +// if (enabled()) { +// return getSpanLog(name).orElse(SpanLogTracingConfig.ENABLED); +// } else { +// return SpanLogTracingConfig.DISABLED; +// } +// } +// +// /** +// * Whether a log event should be logged on the span with a default value. +// * +// * @param logName name of the log event +// * @param defaultValue to use in case the log event is not configured in this span's configuration +// * @return whether to log ({@code true}) the event or not ({@code false}), uses the default value for unconfigured logs +// */ +// public boolean logEnabled(String logName, boolean defaultValue) { +// if (enabled()) { +// return getSpanLog(logName).map(Traceable::enabled).orElse(defaultValue); +// } +// return false; +// } +// +// /** +// * A fluent API builder to create traced span configuration. +// * +// * @param name name of the span +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create traced span configuration from a {@link io.helidon.config.Config}. +// * +// * @param name name of the span +// * @param config config to load span configuration from +// * @return a new traced span configuration +// */ +// public static SpanTracingConfig create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link SpanTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map spanLogMap = new HashMap<>(); +// private final String name; +// private Optional enabled = Optional.empty(); +// private String newName; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public SpanTracingConfig build() { +// final Map finalSpanLogMap = new HashMap<>(spanLogMap); +// final Optional finalNewName = Optional.ofNullable(newName); +// final Optional finalEnabled = enabled; +// +// return new SpanTracingConfig(name) { +// @Override +// public Optional newName() { +// return finalNewName; +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// +// @Override +// protected Optional getSpanLog(String name) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpanLogMap.get(name)); +// } +// return Optional.of(SpanLogTracingConfig.DISABLED); +// } +// }; +// } +// +// /** +// * Configure whether this traced span is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Configure a new name of this span. +// * +// * @param newName new name to use when reporting this span +// * @return updated builder instance +// */ +// public Builder newName(String newName) { +// this.newName = newName; +// return this; +// } +// +// /** +// * Add configuration of a traced span log. +// * +// * @param spanLogTracingConfig configuration of the traced span log +// * @return updated builder instance +// */ +// public Builder addSpanLog(SpanLogTracingConfig spanLogTracingConfig) { +// this.spanLogMap.put(spanLogTracingConfig.name(), spanLogTracingConfig); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of this span +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("new-name").asString().ifPresent(this::newName); +// config.get("logs") +// .asNodeList() +// .ifPresent(nodes -> { +// nodes.forEach(node -> { +// // name is mandatory +// addSpanLog(SpanLogTracingConfig.create(node.get("name").asString().get(), node)); +// }); +// }); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java new file mode 100644 index 00000000000..ff675ee14f8 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java @@ -0,0 +1,56 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Optional; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka Traceable. + * + * Tracing configuration that can be enabled or disabled. + */ +@ConfigBean +public interface FakeTraceableConfig { + /** + * Whether this trace should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not, + * {@code empty} when this flag is not explicitly configured + */ + /*protected*/ Optional isEnabled(); + + /** + * Name of this traceable unit. + * + * @return name + */ + String name(); + + /** + * Whether this traceable should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not + */ + default boolean enabled() { + return isEnabled().orElse(true); + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java new file mode 100644 index 00000000000..2e6c258f71b --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java @@ -0,0 +1,103 @@ +/* + * 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.pico.builder.config.fakes.config; + +/** + * Tracer abstraction. + * Tracer is the central point that collects tracing spans, and (probably) pushes them to backend. + */ +public interface FakeTracer { +// /** +// * Create a no-op tracer. All spans created from this tracer are not doing anything. +// * +// * @return no-op tracer +// */ +// static Tracer noOp() { +// return NoOpTracer.instance(); +// } +// +// /** +// * Get the currently registered global tracer. +// * +// * @return global tracer +// */ +// static Tracer global() { +// return TracerProviderHelper.global(); +// } +// +// /** +// * Register a global tracer, behavior depends on implementation. +// * +// * @param tracer tracer to use as a global tracer +// */ +// +// static void global(Tracer tracer) { +// TracerProviderHelper.global(tracer); +// } +// +// /** +// * Whether this tracer is enabled or not. +// * A no op tracer is disabled. +// * +// * @return {@code true} if this tracer is enabled +// */ +// boolean enabled(); +// +// /** +// * A new span builder to construct {@link io.helidon.tracing.Span}. +// * +// * @param name name of the operation +// * @return a new span builder +// */ +// Span.Builder spanBuilder(String name); +// +// /** +// * Extract parent span context from inbound request, such as from HTTP headers. +// * +// * @param headersProvider provider of headers +// * @return span context of inbound parent span, or empty optional if no span context can be found +// */ +// Optional extract(HeaderProvider headersProvider); +// +// /** +// * Inject current span as a parent for outbound request, such as when invoking HTTP request from a client. +// * +// * @param spanContext current span context +// * @param inboundHeadersProvider provider of inbound headers, may be {@link HeaderProvider#empty()} or headers from original +// * request (if any) +// * @param outboundHeadersConsumer consumer of headers that should be propagated to remote endpoint +// */ +// void inject(SpanContext spanContext, HeaderProvider inboundHeadersProvider, HeaderConsumer outboundHeadersConsumer); +// +// /** +// * Access the underlying tracer by specific type. +// * This is a dangerous operation that will succeed only if the tracer is of expected type. This practically +// * removes abstraction capabilities of this API. +// * +// * @param tracerClass type to access +// * @return instance of the tracer +// * @param type of the tracer +// * @throws java.lang.IllegalArgumentException in case the tracer cannot provide the expected type +// */ +// default T unwrap(Class tracerClass) { +// try { +// return tracerClass.cast(this); +// } catch (ClassCastException e) { +// throw new IllegalArgumentException("This tracer is not compatible with " + tracerClass.getName()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java new file mode 100644 index 00000000000..9515df93034 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java @@ -0,0 +1,244 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka TracingConfig. + * + * Tracing configuration that contains traced components (such as WebServer, Security) and their traced spans and span logs. + * Spans can be renamed through configuration, components, spans and span logs may be disabled through this configuration. + */ +@ConfigBean(key = "tracing") +public interface FakeTracingConfig extends FakeTraceableConfig { +// /** +// * Traced config that is enabled for all components, spans and logs. +// */ +// FakeTracingConfig ENABLED = FakeTracingConfig.builder().build(); +// /** +// * Traced conifg that is disabled for all components, spans and logs. +// */ +// FakeTracingConfig DISABLED = FakeTracingConfig.builder().enabled(false).build(); + +// /** +// * A new traced configuration. +// * +// * @param name name of this configuration, when created using {@link FakeTracingConfig.Builder}, +// * the name is {@code helidon} +// */ +// protected FakeTracingConfig(String name) { +// super(name); +// } +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration or empty if defaults should be used +// */ +// protected abstract Optional getComponent(String componentName); +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration if configured, or an enabled component configuration +// */ +// public ComponentTracingConfig component(String componentName) { +// return component(componentName, true); +// } + + @Singular("component") // Builder::addComponent(String component); Impl::getComponent(String component); + Map components(); + +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @param enabledByDefault whether the component should be enabled or disabled in case it is not configured +// * @return component tracing configuration if configured, or an enabled/disabled component configuration depending on +// * {@code enabledByDefault} +// */ +// public ComponentTracingConfig component(String componentName, boolean enabledByDefault) { +// if (enabled()) { +// return getComponent(componentName) +// .orElseGet(() -> enabledByDefault ? ComponentTracingConfig.ENABLED : ComponentTracingConfig.DISABLED); +// } +// +// return ComponentTracingConfig.DISABLED; +// } +// +// @Override +// public String toString() { +// return "TracingConfig(" + name() + ")"; +// } +// +// /** +// * Create new tracing configuration based on the provided config. +// * +// * @param config configuration of tracing +// * @return tracing configuration +// */ +// public static FakeTracingConfig create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * A fluent API builder for tracing configuration. +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Merge two configurations together. +// * The result will combine configuration from both configurations. In case +// * of conflicts, the {@code newer} wins. +// * +// * @param older older instance to merge +// * @param newer newer (more significant) instance to merge +// * @return a new configuration combining odler and newer +// */ +// public static FakeTracingConfig merge(FakeTracingConfig older, FakeTracingConfig newer) { +// return new FakeTracingConfig(newer.name()) { +// @Override +// public Optional getComponent(String componentName) { +// Optional newerComponent = newer.getComponent(componentName); +// Optional olderComponent = older.getComponent(componentName); +// +// // both configured +// if (newerComponent.isPresent() && olderComponent.isPresent()) { +// return Optional.of(ComponentTracingConfig.merge(olderComponent.get(), newerComponent.get())); +// } +// +// // only newer configured +// if (newerComponent.isPresent()) { +// return newerComponent; +// } +// +// // only older configured +// return olderComponent; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Return configuration of a specific span. +// * This is a shortcut method to {@link #component(String)} and +// * {@link ComponentTracingConfig#span(String)}. +// * +// * @param component component, such as "web-server", "security" +// * @param spanName name of the span, such as "HTTP Request", "security:atn" +// * @return configuration of the span if present in this traced system configuration +// */ +// public SpanTracingConfig spanConfig(String component, String spanName) { +// return component(component).span(spanName); +// } + +// /** +// * Fluent API builder for {@link FakeTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map components = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// +// private Builder() { +// } +// +// @Override +// public FakeTracingConfig build() { +// return new RootTracingConfig("helidon", new HashMap<>(components), enabled); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config Config with tracing configuration +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// Config compConfig = config.get("components"); +// compConfig.asNodeList() +// .ifPresent(compList -> { +// compList.forEach(componentConfig -> addComponent(ComponentTracingConfig.create(componentConfig.name(), +// componentConfig))); +// }); +// +// return this; +// } +// +// /** +// * Add a traced component configuration. +// * +// * @param component configuration of this component's tracing +// * @return updated builder instance +// */ +// public Builder addComponent(ComponentTracingConfig component) { +// components.put(component.name(), component); +// return this; +// } +// +// /** +// * Whether overall tracing is enabled. +// * If tracing is disabled on this level, all traced components and spans are disabled - even if explicitly configured +// * as enabled. +// * +// * @param enabled set to {@code false} to disable tracing for any component and span +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +// +// static final class RootTracingConfig extends FakeTracingConfig { +// private final Map components; +// private final Optional enabled; +// +// RootTracingConfig(String name, +// Map components, +// Optional enabled) { +// super(name); +// this.components = components; +// this.enabled = enabled; +// } +// +// @Override +// public Optional getComponent(String componentName) { +// return Optional.ofNullable(components.get(componentName)); +// } +// +// @Override +// public Optional isEnabled() { +// return enabled; +// } +// +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java new file mode 100644 index 00000000000..5f1213c1484 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java @@ -0,0 +1,438 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.security.SecureRandom; +import java.util.Collection; +import java.util.Random; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.common.LazyValue; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka WebServerTls. + * + * A class wrapping transport layer security (TLS) configuration for + * WebServer sockets. + */ +@ConfigBean +public interface FakeWebServerTlsConfig { + String PROTOCOL = "TLS"; + // secure random cannot be stored in native image, it must be initialized at runtime + LazyValue RANDOM = LazyValue.create(SecureRandom::new); + + /** + * This constant is a context classifier for the x509 client certificate if it is present. Callers may use this + * constant to lookup the client certificate associated with the current request context. + */ + String CLIENT_X509_CERTIFICATE = FakeWebServerTlsConfig.class.getName() + ".client-x509-certificate"; + +// private final Set enabledTlsProtocols; +// private final Set cipherSuite; +// private final SSLContext sslContext; +// private final boolean enabled; +// private final ClientAuthentication clientAuth; +// +// private FakeWebServerTlsConfigBean(Builder builder) { +// this.enabledTlsProtocols = Set.copyOf(builder.enabledTlsProtocols); +// this.cipherSuite = builder.cipherSuite; +// this.sslContext = builder.sslContext; +// this.enabled = (null != sslContext); +// this.clientAuth = builder.clientAuth; +// } +// +// /** +// * A fluent API builder for {@link FakeWebServerTlsConfigBean}. +// * +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create TLS configuration from config. +// * +// * @param config located on the node of the tls configuration (usually this is {@code ssl}) +// * @return a new TLS configuration +// */ +// public static FakeWebServerTlsConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// + + Collection enabledTlsProtocols(); +// { +// return enabledTlsProtocols; +// } +// + + SSLContext sslContext(); +// { +// return sslContext; +// } + +// ClientAuthentication clientAuth() { +// return clientAuth; +// } + + @Singular("cipher") + Set cipherSuite(); +// { +// return cipherSuite; +// } + + /** + * Whether this TLS config has security enabled (and the socket is going to be + * protected by one of the TLS protocols), or no (and the socket is going to be plain). + * + * @return {@code true} if this configuration represents a TLS configuration, {@code false} for plain configuration + */ + boolean enabled(); +// { +// return enabled; +// } +// +// /** +// * Fluent API builder for {@link FakeWebServerTlsConfigBean}. +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private final Set enabledTlsProtocols = new HashSet<>(); +// +// private SSLContext sslContext; +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeoutSeconds; +// +// private boolean enabled; +// private Boolean explicitEnabled; +// private ClientAuthentication clientAuth; +// private Set cipherSuite = Set.of(); +// +// private Builder() { +// clientAuth = ClientAuthentication.NONE; +// } +// +// @Override +// public FakeWebServerTlsConfigBean build() { +// boolean enabled; +// +// if (null == explicitEnabled) { +// enabled = this.enabled; +// } else { +// enabled = explicitEnabled; +// } +// +// if (!enabled) { +// this.sslContext = null; +// // ssl is disabled +// return new FakeWebServerTlsConfigBean(this); +// } +// +// if (null == sslContext) { +// // no explicit ssl context, build it using private key and trust store +// sslContext = newSSLContext(); +// } +// +// return new FakeWebServerTlsConfigBean(this); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config config on the node of SSL configuration +// * @return this builder +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// if (explicitEnabled != null && !explicitEnabled) { +// return this; +// } +// +// config.get("client-auth").asString().ifPresent(this::clientAuth); +// config.get("private-key") +// .ifExists(it -> privateKey(FakeKeyConfig.create(it))); +// +// config.get("trust") +// .ifExists(it -> trust(FakeKeyConfig.create(it))); +// +// config.get("protocols").asList(String.class).ifPresent(this::enabledProtocols); +// config.get("session-cache-size").asLong().ifPresent(this::sessionCacheSize); +// config.get("cipher-suite").asList(String.class).ifPresent(this::allowedCipherSuite); +// DeprecatedConfig.get(config, "session-timeout-seconds", "session-timeout") +// .asLong() +// .ifPresent(this::sessionTimeoutSeconds); +// +// return this; +// } +// +// private void clientAuth(String it) { +// clientAuth(ClientAuthentication.valueOf(it.toUpperCase())); +// } +// +// /** +// * Configures whether client authentication will be required or not. +// * +// * @param clientAuth client authentication +// * @return this builder +// */ +// @ConfiguredOption("none") +// public Builder clientAuth(ClientAuthentication clientAuth) { +// this.clientAuth = Objects.requireNonNull(clientAuth); +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param context a SSL context to use +// * @return this builder +// */ +// public Builder sslContext(SSLContext context) { +// this.enabled = true; +// this.sslContext = context; +// return this; +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * @param protocols protocols to enable, if empty, enables defaults +// * +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(String... protocols) { +// return enabledProtocols(Arrays.asList(Objects.requireNonNull(protocols))); +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * +// * @param protocols protocols to enable, if empty enables +// * the default protocols +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(Collection protocols) { +// Objects.requireNonNull(protocols); +// +// this.enabledTlsProtocols.clear(); +// this.enabledTlsProtocols.addAll(protocols); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// @ConfiguredOption(required = true) +// public Builder privateKey(FakeKeyConfig privateKeyConfig) { +// // setting private key, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.privateKeyConfig = Objects.requireNonNull(privateKeyConfig); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfigBuilder the required private key configuration parameter +// * @return this builder +// */ +// public Builder privateKey(Supplier privateKeyConfigBuilder) { +// return privateKey(privateKeyConfigBuilder.get()); +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return this builder +// */ +// @ConfiguredOption +// public Builder trust(FakeKeyConfig trustConfig) { +// // setting explicit trust, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.trustConfig = Objects.requireNonNull(trustConfig); +// return this; +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfigBuilder the trust configuration builder +// * @return this builder +// */ +// public Builder trust(Supplier trustConfigBuilder) { +// return trust(trustConfigBuilder.get()); +// } +// +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionTimeoutSeconds(long sessionTimeout) { +// this.sessionTimeoutSeconds = sessionTimeout; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param timeout the session timeout amount +// * @param unit the session timeout time unit +// * @return this builder +// */ +// public Builder sessionTimeout(long timeout, TimeUnit unit) { +// this.sessionTimeoutSeconds = unit.toSeconds(timeout); +// return this; +// } +// +// /** +// * Set allowed cipher suite. If an empty collection is set, an exception is thrown since +// * it is required to support at least some ciphers. +// * +// * @param cipherSuite allowed cipher suite +// * @return an updated builder +// */ +// @ConfiguredOption(key = "cipher-suite") +// public Builder allowedCipherSuite(List cipherSuite) { +// Objects.requireNonNull(cipherSuite); +// if (cipherSuite.isEmpty()) { +// throw new IllegalStateException("Allowed cipher suite has to have at least one cipher specified"); +// } +// this.cipherSuite = Set.copyOf(cipherSuite); +// return this; +// } +// +// /** +// * Whether the TLS config should be enabled or not. +// * +// * @param enabled configure to {@code false} to disable SSL context (and SSL support on the server) +// * @return this builder +// */ +// @ConfiguredOption(description = "Can be used to disable TLS even if keys are configured.", value = "true") +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// this.explicitEnabled = enabled; +// return this; +// } +// +// private SSLContext newSSLContext() { +// try { +// if (null == privateKeyConfig) { +// throw new IllegalStateException("Private key must be configured when SSL is enabled."); +// } +// KeyManagerFactory kmf = buildKmf(this.privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(this.trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (this.sessionTimeoutSeconds > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeoutSeconds, Integer.MAX_VALUE)); +// } +// return ctx; +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Failed to build server SSL Context!", e); +// } +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.get().nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java new file mode 100644 index 00000000000..c674fed80e4 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java @@ -0,0 +1,201 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Random; + +import io.helidon.pico.builder.Builder; + +/** + * aka SSLContextBuilder. + */ +@Builder +public interface SSLContextConfig { + + String PROTOCOL = "TLS"; + Random RANDOM = new Random(); + +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeout; +// +// private SSLContextConfig() { +// } +// + +// /** +// * Creates a builder of the {@link javax.net.ssl.SSLContext}. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// public static SSLContextConfig create(FakeKeyConfig privateKeyConfig) { +// return new SSLContextConfig().privateKeyConfig(privateKeyConfig); +// } + +// /** +// * Creates {@link javax.net.ssl.SSLContext} from the provided configuration. +// * +// * @param sslConfig the ssl configuration +// * @return a built {@link javax.net.ssl.SSLContext} +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// static SSLContext create(Config sslConfig) { +// return new SSLContextConfig().privateKeyConfig(FakeKeyConfig.create(sslConfig.get("private-key"))) +// .sessionCacheSize(sslConfig.get("session-cache-size").asInt().orElse(0)) +// .sessionTimeout(sslConfig.get("session-timeout").asInt().orElse(0)) +// .trustConfig(FakeKeyConfig.create(sslConfig.get("trust"))) +// .build(); +// } +// +// private SSLContextConfig privateKeyConfig(FakeKeyConfig privateKeyConfig) { +// this.privateKeyConfig = privateKeyConfig; +// return this; +// } + + FakeKeyConfig privateKeyConfig(); + +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return an updated builder +// */ +// public SSLContextConfig trustConfig(FakeKeyConfig trustConfig) { +// this.trustConfig = trustConfig; +// return this; +// } + + FakeKeyConfig trustConfig(); + +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return an updated builder +// */ +// public SSLContextConfig sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } + + long sessionCacheSize(); + +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return an updated builder +// */ +// public SSLContextConfig sessionTimeout(long sessionTimeout) { +// this.sessionTimeout = sessionTimeout; +// return this; +// } + + long sessionTimeout(); + +// /** +// * Create new {@code {@link javax.net.ssl.SSLContext}} instance with configured settings. +// * +// * @return the SSL Context built instance +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// public SSLContext build() { +// Objects.requireNonNull(privateKeyConfig, "The private key config must be set!"); +// +// try { +// return newSSLContext(privateKeyConfig, trustConfig, sessionCacheSize, sessionTimeout); +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Building of the SSLContext of unsuccessful!", e); +// } +// } + +// private static SSLContext newSSLContext(FakeKeyConfig privateKeyConfig, +// FakeKeyConfig trustConfig, +// long sessionCacheSize, +// long sessionTimeout) +// throws IOException, GeneralSecurityException { +// KeyManagerFactory kmf = buildKmf(privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (sessionTimeout > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE)); +// } +// return ctx; +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java new file mode 100644 index 00000000000..2636622a275 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java @@ -0,0 +1,36 @@ +/* + * 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.pico.builder.config.test.testsubjects; + +import java.util.Map; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.testsubjects.CommonConfig; + +@ConfigBean(drivesActivation = false) +public interface ClientConfig extends CommonConfig { + + @ConfiguredOption("default") + @Override + String name(); + + int serverPort(); + + Map headers(); + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java new file mode 100644 index 00000000000..8c6d70d2d86 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java @@ -0,0 +1,36 @@ +/* + * 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.pico.builder.config.testsubjects; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; + +@ConfigBean +public interface CommonConfig { + + String name(); + + @ConfiguredOption(required = true) + int port(); + + List cipherSuites(); + + char[] pwd(); + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java new file mode 100644 index 00000000000..9dcd7bf600e --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.testsubjects; + +import java.util.Optional; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; + +@ConfigBean(atLeastOne = true) +public interface ServerConfig extends CommonConfig { + + @ConfiguredOption("default") + @Override + String name(); + + Optional description(); + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/module-info.java b/pico/builder-config/tests/configbean/src/main/java/module-info.java new file mode 100644 index 00000000000..0db7b6f92a7 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/module-info.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +/** + * Pico ConfigBean Builder test module. + */ +module io.helidon.pico.builder.config.tests.test.config { + requires static jakarta.inject; + requires static jakarta.annotation; + + requires static io.helidon.config.metadata; + + requires io.helidon.common; + requires io.helidon.common.config; + requires io.helidon.pico; + requires io.helidon.pico.builder.config; + requires io.helidon.pico.builder; +} diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java new file mode 100644 index 00000000000..f66904e5e6a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java @@ -0,0 +1,71 @@ +/* + * 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.pico.builder.config.test; + +import java.util.Map; + +import io.helidon.config.Config; +import io.helidon.config.ConfigSources; +import io.helidon.pico.builder.config.testsubjects.DefaultServerConfig; +import io.helidon.pico.builder.config.testsubjects.ServerConfig; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +class BasicConfigBeanTest { + + @Test + void acceptConfig() { + Config cfg = Config.create( + ConfigSources.create( + Map.of("name", "server", + "port", "8080", + "description", "test", + "pwd", "pwd1" +// , "cipher-suites", "a,b,c" // no List mapper available --- discuss w/ tlanger + ), + "my-simple-config-1")); + ServerConfig serverConfig = DefaultServerConfig.toBuilder(cfg).build(); + + assertThat(serverConfig.description(), optionalValue(equalTo("test"))); + assertThat(serverConfig.name(), equalTo("server")); + assertThat(serverConfig.port(), equalTo(8080)); +// assertThat(serverConfig.cipherSuites(), hasSize(3)); +// assertThat(serverConfig.cipherSuites(), contains("a", "b", "c")); + assertThat(new String(serverConfig.pwd()), equalTo("pwd1")); + assertThat(serverConfig.toString(), + startsWith("ServerConfig")); + assertThat(serverConfig.toString(), + endsWith("(name=server, port=8080, cipherSuites=[], pwd=not-null, description=Optional[test])")); + } + + @Test + void emptyConfig() { + Config cfg = Config.create(); + ServerConfig serverConfig = DefaultServerConfig.toBuilder(cfg).build(); + assertThat(serverConfig.description(), optionalEmpty()); + assertThat(serverConfig.name(), equalTo("default")); + assertThat(serverConfig.port(), equalTo(0)); + } + +} diff --git a/pico/builder-config/tests/pom.xml b/pico/builder-config/tests/pom.xml new file mode 100644 index 00000000000..c1397a3b1d1 --- /dev/null +++ b/pico/builder-config/tests/pom.xml @@ -0,0 +1,49 @@ + + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + + true + true + true + true + true + true + + + io.helidon.pico.builder.config.tests + helidon-pico-builder-config-tests-project + Helidon Pico Builder Config Tests Project + pom + + + configbean + + + diff --git a/pico/builder/pom.xml b/pico/builder/pom.xml index 4d940e94523..9baea8f15fe 100644 --- a/pico/builder/pom.xml +++ b/pico/builder/pom.xml @@ -36,6 +36,11 @@ Helidon Pico Builder Project pom + + + 11 + + builder processor-spi diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java index a5cd612e864..dfb8946bcfb 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java @@ -45,6 +45,8 @@ * Represents the context of the body being code generated. */ public class BodyContext { + static final String TAG_META_PROPS = "__META_PROPS"; + private final boolean doingConcreteType; private final TypeName implTypeName; private final TypeInfo typeInfo; @@ -110,7 +112,7 @@ public class BodyContext { * * @return true if we are processing the concrete type */ - protected boolean doingConcreteType() { + public boolean doingConcreteType() { return doingConcreteType; } @@ -119,7 +121,7 @@ protected boolean doingConcreteType() { * * @return the type name */ - protected TypeName implTypeName() { + public TypeName implTypeName() { return implTypeName; } @@ -128,7 +130,7 @@ protected TypeName implTypeName() { * * @return the type info */ - protected TypeInfo typeInfo() { + public TypeInfo typeInfo() { return typeInfo; } @@ -137,7 +139,7 @@ protected TypeInfo typeInfo() { * * @return the builder annotation */ - protected AnnotationAndValue builderAnnotation() { + public AnnotationAndValue builderAnnotation() { return builderAnnotation; } @@ -155,7 +157,7 @@ protected Map map() { * * @return the list of type elements */ - protected List allTypeInfos() { + public List allTypeInfos() { return allTypeInfos; } @@ -164,7 +166,7 @@ protected List allTypeInfos() { * * @return the list of attribute names */ - protected List allAttributeNames() { + public List allAttributeNames() { return allAttributeNames; } @@ -173,7 +175,7 @@ protected List allAttributeNames() { * * @return the parent type name */ - protected AtomicReference parentTypeName() { + public AtomicReference parentTypeName() { return parentTypeName; } @@ -236,7 +238,7 @@ protected boolean isBeanStyleRequired() { * * @return the list type */ - protected String listType() { + public String listType() { return listType; } @@ -245,7 +247,7 @@ protected String listType() { * * @return the map type */ - protected String mapType() { + public String mapType() { return mapType; } @@ -254,7 +256,7 @@ protected String mapType() { * * @return the set type */ - protected String setType() { + public String setType() { return setType; } @@ -263,7 +265,7 @@ protected String setType() { * * @return true if current has parent */ - protected boolean hasParent() { + public boolean hasParent() { return hasParent; } @@ -281,7 +283,7 @@ protected TypeName ctorBuilderAcceptTypeName() { * * @return the generic declaration */ - protected String genericBuilderClassDecl() { + public String genericBuilderClassDecl() { return genericBuilderClassDecl; } diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java index 7483543ffa2..54beea7e0a3 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java @@ -49,6 +49,7 @@ import io.helidon.pico.types.TypeName; import io.helidon.pico.types.TypedElementName; +import static io.helidon.pico.builder.processor.tools.BodyContext.TAG_META_PROPS; import static io.helidon.pico.builder.processor.tools.BodyContext.toBeanAttributeName; /** @@ -201,6 +202,7 @@ protected String toBody(BodyContext ctx) { appendExtraMethods(builder, ctx); appendToBuilderMethods(builder, ctx); appendBuilder(builder, ctx); + appendExtraBuilderMethods(builder, ctx); appendExtraInnerClasses(builder, ctx); appendFooter(builder, ctx); return builder.toString(); @@ -209,11 +211,11 @@ protected String toBody(BodyContext ctx) { /** * Appends the footer of the generated class. * - * @param builder the builder - * @param ignoredCtx the context + * @param builder the builder + * @param ctx the context */ protected void appendFooter(StringBuilder builder, - BodyContext ignoredCtx) { + BodyContext ctx) { builder.append("}\n"); } @@ -272,8 +274,7 @@ protected void appendMetaAttributes(StringBuilder builder, builder.append("\t\tMap> metaProps = new java.util.LinkedHashMap<>();\n"); AtomicBoolean needsCustomMapOf = new AtomicBoolean(); - appendMetaProps(builder, "metaProps", - ctx.typeInfo(), ctx.map(), ctx.allAttributeNames(), ctx.allTypeInfos(), needsCustomMapOf); + appendMetaProps(builder, ctx, "metaProps", needsCustomMapOf); builder.append("\t\treturn metaProps;\n"); builder.append("\t}\n\n"); @@ -302,7 +303,7 @@ protected void appendFields(StringBuilder builder, String beanAttributeName = ctx.allAttributeNames().get(i); appendAnnotations(builder, method.annotations(), "\t"); builder.append("\tprivate "); - builder.append(getFieldModifier()); + builder.append(fieldModifier()); builder.append(toGenerics(method, false)).append(" "); builder.append(beanAttributeName).append(";\n"); } @@ -347,6 +348,11 @@ protected void appendHeader(StringBuilder builder, } else { if (ctx.hasParent()) { builder.append(toAbstractImplTypeName(ctx.parentTypeName().get(), ctx.builderAnnotation()).get()); + } else { + Optional baseExtendsTypeName = baseExtendsTypeName(ctx); + if (baseExtendsTypeName.isPresent()) { + builder.append(" extends ").append(baseExtendsTypeName.get().fqName()).append("\n\t\t\t\t\t\t\t\t\t\t"); + } } if (!ctx.hasParent() && ctx.hasStreamSupportOnImpl()) { @@ -358,11 +364,54 @@ protected void appendHeader(StringBuilder builder, if (!ctx.hasParent() && ctx.hasStreamSupportOnImpl()) { builder.append(", Supplier<").append(ctx.genericBuilderAcceptAliasDecl()).append(">"); } + + List extraImplementContracts = extraImplementedTypeNames(ctx); + extraImplementContracts.forEach(t -> builder.append(",\n\t\t\t\t\t\t\t\t\t\t\t").append(t.fqName())); } builder.append(" {\n"); } + /** + * Returns any extra 'extends' type name that should be on the main generated type at the base level. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected Optional baseExtendsTypeName(BodyContext ctx) { + return Optional.empty(); + } + + /** + * Returns any extra 'extends' type name that should be on the main generated builder type at the base level. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected Optional baseExtendsBuilderTypeName(BodyContext ctx) { + return Optional.empty(); + } + + /** + * Returns any extra 'implements' contract types that should be on the main generated type. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected List extraImplementedTypeNames(BodyContext ctx) { + return List.of(); + } + + /** + * Returns any extra 'implements' contract types that should be on the main generated builder type. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected List extraImplementedBuilderContracts(BodyContext ctx) { + return List.of(); + } + /** * Adds extra imports to the generated builder. * @@ -401,10 +450,26 @@ protected void appendToStringMethod(StringBuilder builder, builder.append("\t@Override\n"); builder.append("\tpublic String toString() {\n"); builder.append("\t\treturn ").append(ctx.typeInfo().typeName()); - builder.append(".class.getSimpleName() + \"(\" + toStringInner() + \")\";\n"); + builder.append(".class.getSimpleName() + "); + + String instanceIdRef = instanceIdRef(ctx); + if (!instanceIdRef.isBlank()) { + builder.append("\"{\" + ").append(instanceIdRef).append(" + \"}\" + "); + } + builder.append("\"(\" + toStringInner() + \")\";\n"); builder.append("\t}\n\n"); } + /** + * The nuanced instance id for the {@link #appendToStringMethod(StringBuilder, BodyContext)}. + * + * @param ctx the context + * @return the instance id + */ + protected String instanceIdRef(BodyContext ctx) { + return ""; + } + /** * Adds extra methods to the generated builder. This base implementation will generate the visitAttributes() for the main * generated class. @@ -415,7 +480,7 @@ protected void appendToStringMethod(StringBuilder builder, protected void appendExtraMethods(StringBuilder builder, BodyContext ctx) { if (ctx.includeMetaAttributes()) { - appendVisitAttributes(builder, "", false, ctx); + appendVisitAttributes(builder, ctx, "", false); } } @@ -428,7 +493,7 @@ protected void appendExtraMethods(StringBuilder builder, */ protected void appendExtraInnerClasses(StringBuilder builder, BodyContext ctx) { - GenerateVisitor.appendAttributeVisitors(builder, ctx); + GenerateVisitorSupport.appendExtraInnerClasses(builder, ctx); } /** @@ -436,7 +501,7 @@ protected void appendExtraInnerClasses(StringBuilder builder, * * @return the field modifier */ - protected String getFieldModifier() { + protected String fieldModifier() { return "final "; } @@ -444,15 +509,19 @@ protected String getFieldModifier() { * Appends the visitAttributes() method on the generated class. * * @param builder the builder + * @param ctx the context * @param extraTabs spacing * @param beanNameRef refer to bean name? otherwise refer to the element name - * @param ctx the context */ protected void appendVisitAttributes(StringBuilder builder, + BodyContext ctx, String extraTabs, - boolean beanNameRef, - BodyContext ctx) { - if (ctx.hasParent()) { + boolean beanNameRef) { + if (ctx.doingConcreteType()) { + return; + } + + if (overridesVisitAttributes(ctx)) { builder.append(extraTabs).append("\t@Override\n"); } else { GenerateJavadoc.visitAttributes(builder, ctx, extraTabs); @@ -468,18 +537,18 @@ protected void appendVisitAttributes(StringBuilder builder, TypedElementName method = ctx.allTypeInfos().get(i); String typeName = method.typeName().declaredName(); List typeArgs = method.typeName().typeArguments().stream() - .map(it -> it.declaredName() + ".class") + .map(it -> normalize(it.declaredName()) + ".class") .collect(Collectors.toList()); String typeArgsStr = String.join(", ", typeArgs); - builder.append(extraTabs).append("\t\tvisitor.visit(\"").append(attrName).append("\", () -> "); + builder.append(extraTabs).append("\t\tvisitor.visit(\"").append(attrName).append("\", () -> this."); if (beanNameRef) { builder.append(attrName).append(", "); } else { builder.append(method.elementName()).append("(), "); } - builder.append("META_PROPS.get(\"").append(attrName).append("\"), userDefinedCtx, "); - builder.append(typeName).append(".class"); + builder.append(TAG_META_PROPS).append(".get(\"").append(attrName).append("\"), userDefinedCtx, "); + builder.append(normalize(typeName)).append(".class"); if (!typeArgsStr.isBlank()) { builder.append(", ").append(typeArgsStr); } @@ -491,18 +560,26 @@ protected void appendVisitAttributes(StringBuilder builder, builder.append(extraTabs).append("\t}\n\n"); } + /** + * Return true if the visitAttributes() methods is being overridden. + * + * @param ctx the context + * @return true if overriding visitAttributes(); + */ + protected boolean overridesVisitAttributes(BodyContext ctx) { + return ctx.hasParent(); + } + /** * Adds extra default ctor code. * * @param builder the builder - * @param hasParent true if there is a parent for the generated type + * @param ctx the context * @param builderTag the tag (variable name) used for the builder arg - * @param typeInfo the type info */ protected void appendExtraCtorCode(StringBuilder builder, - boolean hasParent, - String builderTag, - TypeInfo typeInfo) { + BodyContext ctx, + String builderTag) { } /** @@ -525,8 +602,8 @@ protected void appendExtraFields(StringBuilder builder, BodyContext ctx) { if (!ctx.doingConcreteType() && ctx.includeMetaAttributes()) { GenerateJavadoc.internalMetaPropsField(builder); - builder.append("\tprotected static final Map> META_PROPS = " - + "Collections.unmodifiableMap(__calcMeta());\n"); + builder.append("\tprotected static final Map> ") + .append(TAG_META_PROPS).append(" = Collections.unmodifiableMap(__calcMeta());\n"); } } @@ -534,32 +611,22 @@ protected void appendExtraFields(StringBuilder builder, * Adds extra toBuilder() methods. * * @param builder the builder - * @param decl the declaration template for the toBuilder method * @param ctx the context + * @param decl the declaration template for the toBuilder method */ protected void appendExtraToBuilderBuilderFunctions(StringBuilder builder, - String decl, - BodyContext ctx) { + BodyContext ctx, + String decl) { } /** * Adds extra builder methods. * - * @param builder the builder - * @param builderGeneratedClassName the builder class name (as written in source form) - * @param builderAnnotation the builder annotation - * @param typeInfo the type info - * @param parentTypeName the parent type name - * @param allAttributeNames all the bean attribute names belonging to the builder - * @param allTypeInfos all the methods belonging to the builder + * @param builder the builder + * @param ctx the context */ protected void appendExtraBuilderFields(StringBuilder builder, - String builderGeneratedClassName, - AnnotationAndValue builderAnnotation, - TypeInfo typeInfo, - TypeName parentTypeName, - List allAttributeNames, - List allTypeInfos) { + BodyContext ctx) { } /** @@ -581,34 +648,26 @@ protected void appendBuilderBuildPreSteps(StringBuilder builder, */ protected void appendExtraBuilderMethods(StringBuilder builder, BodyContext ctx) { - if (ctx.doingConcreteType()) { - return; + if (!ctx.doingConcreteType() && ctx.includeMetaAttributes()) { + appendVisitAttributes(builder, ctx, "\t", true); } - if (ctx.includeMetaAttributes()) { - appendVisitAttributes(builder, "\t", true, ctx); - } + builder.append("\t}\n\n"); } /** * Adds extra meta properties to the generated code. * * @param builder the builder + * @param ctx the context * @param tag the tag used to represent the meta props variable on the generated code - * @param typeInfo the type info - * @param map the map of all the methods - * @param allAttributeNames all the bean attribute names belonging to the builder - * @param allTypeInfos all the methods belonging to the builder * @param needsCustomMapOf will be set to true if a custom map.of() function needs to be generated (i.e., if over 9 tuples) */ protected void appendMetaProps(StringBuilder builder, + BodyContext ctx, String tag, - TypeInfo typeInfo, - Map map, - List allAttributeNames, - List allTypeInfos, AtomicBoolean needsCustomMapOf) { - map.forEach((attrName, method) -> + ctx.map().forEach((attrName, method) -> builder.append("\t\t") .append(tag) .append(".put(\"") @@ -636,18 +695,18 @@ protected String normalizeConfiguredOptionKey(String key, * Appends the singular setter methods on the builder. * * @param builder the builder + * @param ctx the context * @param method the method * @param beanAttributeName the bean attribute name * @param isList true if the output involves List type * @param isMap true if the output involves Map type * @param isSet true if the output involves Set type - * @param ctx the context */ protected void maybeAppendSingularSetter(StringBuilder builder, + BodyContext ctx, TypedElementName method, String beanAttributeName, - boolean isList, boolean isMap, boolean isSet, - BodyContext ctx) { + boolean isList, boolean isMap, boolean isSet) { String singularVal = toValue(Singular.class, method, false, false).orElse(null); if (Objects.nonNull(singularVal) && (isList || isMap || isSet)) { char[] methodName = reverseBeanName(singularVal.isBlank() ? maybeSingularFormOf(beanAttributeName) : singularVal); @@ -673,17 +732,16 @@ protected static String maybeSingularFormOf(String beanAttributeName) { * Append the setters for the given bean attribute name. * * @param mainBuilder the builder + * @param ctx the body context * @param beanAttributeName the bean attribute name * @param methodName the method name * @param method the method - * @param ctx the body context */ protected void appendSetter(StringBuilder mainBuilder, + BodyContext ctx, String beanAttributeName, String methodName, - TypedElementName method, - BodyContext ctx) { - + TypedElementName method) { TypeName typeName = method.typeName(); boolean isList = typeName.isList(); boolean isMap = !isList && typeName.isMap(); @@ -695,11 +753,6 @@ protected void appendSetter(StringBuilder mainBuilder, builder.append("\t\tpublic ").append(ctx.genericBuilderAliasDecl()).append(" ").append(methodName).append("(") .append(toGenerics(method, upLevel)).append(" val) {\n"); - /* - Make sure that arguments are not null - */ - builder.append("\t\t\tObjects.requireNonNull(val);\n"); - /* Assign field, or update collection */ @@ -710,21 +763,21 @@ protected void appendSetter(StringBuilder mainBuilder, builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".addAll(val);\n"); + .append(".addAll(Objects.requireNonNull(val));\n"); } else if (isMap) { builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".putAll(val);\n"); + .append(".putAll(Objects.requireNonNull(val));\n"); } else if (isSet) { builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".addAll(val);\n"); + .append(".addAll(Objects.requireNonNull(val));\n"); } else if (typeName.array()) { builder.append(" = val.clone();\n"); } else { - builder.append(" = val;\n"); + builder.append(" = Objects.requireNonNull(val);\n"); } builder.append("\t\t\treturn identity();\n"); builder.append("\t\t}\n\n"); @@ -964,11 +1017,10 @@ private String toImplTypeSuffix(AnnotationAndValue builderAnnotation) { private void appendBuilder(StringBuilder builder, BodyContext ctx) { appendBuilderHeader(builder, ctx); - appendExtraBuilderFields(builder, ctx.genericBuilderClassDecl(), ctx.builderAnnotation(), - ctx.typeInfo(), ctx.parentTypeName().get(), ctx.allAttributeNames(), ctx.allTypeInfos()); + appendExtraBuilderFields(builder, ctx); appendBuilderBody(builder, ctx); - appendExtraBuilderMethods(builder, ctx); +// appendExtraBuilderMethods(builder, ctx); if (ctx.doingConcreteType()) { if (ctx.hasParent()) { @@ -990,7 +1042,7 @@ private void appendBuilder(StringBuilder builder, boolean isMap = !isList && typeName.isMap(); boolean isSet = !isMap && typeName.isSet(); boolean ignoredUpLevel = isSet || isList; - appendSetter(builder, beanAttributeName, beanAttributeName, method, ctx); + appendSetter(builder, ctx, beanAttributeName, beanAttributeName, method); if (!isList && !isMap && !isSet) { boolean isBoolean = BeanUtils.isBooleanType(typeName.name()); if (isBoolean && beanAttributeName.startsWith("is")) { @@ -999,12 +1051,12 @@ private void appendBuilder(StringBuilder builder, + Character.toLowerCase(beanAttributeName.charAt(2)) + beanAttributeName.substring(3); if (!ctx.allAttributeNames().contains(basicAttributeName)) { - appendSetter(builder, beanAttributeName, basicAttributeName, method, ctx); + appendSetter(builder, ctx, beanAttributeName, basicAttributeName, method); } } } - maybeAppendSingularSetter(builder, method, beanAttributeName, isList, isMap, isSet, ctx); + maybeAppendSingularSetter(builder, ctx, method, beanAttributeName, isList, isMap, isSet); i++; } @@ -1040,7 +1092,11 @@ private void appendBuilder(StringBuilder builder, } } - GenerateJavadoc.accept(builder); + if (ctx.hasParent()) { + builder.append("\t\t@Override\n"); + } else { + GenerateJavadoc.accept(builder); + } builder.append("\t\tpublic ") .append(ctx.genericBuilderAliasDecl()) .append(" accept(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); @@ -1048,11 +1104,11 @@ private void appendBuilder(StringBuilder builder, if (ctx.hasParent()) { builder.append("\t\t\tsuper.accept(val);\n"); } - builder.append("\t\t\tacceptThis(val);\n"); + builder.append("\t\t\t__acceptThis(val);\n"); builder.append("\t\t\treturn identity();\n"); builder.append("\t\t}\n\n"); - builder.append("\t\tprivate void acceptThis(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); + builder.append("\t\tprivate void __acceptThis(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); i = 0; for (String beanAttributeName : ctx.allAttributeNames()) { @@ -1070,14 +1126,12 @@ private void appendBuilder(StringBuilder builder, } builder.append("val.").append(getterName).append("());\n"); } - builder.append("\t\t}\n"); + builder.append("\t\t}\n\n"); } - - // end of the generated builder inner class here - builder.append("\t}\n"); } - private void appendBuilderBody(StringBuilder builder, BodyContext ctx) { + private void appendBuilderBody(StringBuilder builder, + BodyContext ctx) { if (!ctx.doingConcreteType()) { // prepare builder fields, starting with final (list, map, set) boolean hasFinal = false; @@ -1198,9 +1252,20 @@ private void appendBuilderHeader(StringBuilder builder, builder.append("<").append(ctx.genericBuilderAliasDecl()) .append(", ").append(ctx.genericBuilderAcceptAliasDecl()); builder.append(">"); - } else if (ctx.hasStreamSupportOnBuilder()) { + } else { + Optional baseExtendsTypeName = baseExtendsBuilderTypeName(ctx); + if (baseExtendsTypeName.isPresent()) { + builder.append("\n\t\t\t\t\t\t\t\t\t\t" + + "extends ") + .append(baseExtendsTypeName.get().fqName()) + .append("\n\t\t\t\t\t\t\t\t\t\t"); + } + } + + if (ctx.hasStreamSupportOnBuilder()) { builder.append("implements Supplier<").append(ctx.genericBuilderAcceptAliasDecl()).append(">"); } + if (!ctx.hasParent()) { if (ctx.requireLibraryDependencies()) { builder.append(", io.helidon.common.Builder<").append(ctx.genericBuilderAliasDecl()) @@ -1211,6 +1276,9 @@ private void appendBuilderHeader(StringBuilder builder, } } + List extraImplementBuilderContracts = extraImplementedBuilderContracts(ctx); + extraImplementBuilderContracts.forEach(t -> builder.append(",\n\t\t\t\t\t\t\t\t\t\t\t").append(t.fqName())); + builder.append(" {\n"); } } @@ -1221,10 +1289,8 @@ private void appendToBuilderMethods(StringBuilder builder, return; } - GenerateMethod.builderMethods(builder, ctx); - - String decl = "public static Builder toBuilder({args}) {"; - appendExtraToBuilderBuilderFunctions(builder, decl, ctx); + String decl = GenerateMethod.builderMethods(builder, ctx); + appendExtraToBuilderBuilderFunctions(builder, ctx, decl); } private void appendInterfaceBasedGetters(StringBuilder builder, @@ -1248,7 +1314,6 @@ private void appendInterfaceBasedGetters(StringBuilder builder, private void appendCtor(StringBuilder builder, BodyContext ctx) { - GenerateJavadoc.typeConstructorWithBuilder(builder); builder.append("\tprotected ").append(ctx.implTypeName().className()); builder.append("("); @@ -1261,13 +1326,47 @@ private void appendCtor(StringBuilder builder, builder.append(""); } builder.append(" b) {\n"); - appendExtraCtorCode(builder, ctx.hasParent(), "b", ctx.typeInfo()); - appendCtorCode(builder, "b", ctx); + appendExtraCtorCode(builder, ctx, "b"); + appendCtorCodeBody(builder, ctx, "b"); +// builder.append("\t}\n"); } builder.append("\t}\n\n"); } + /** + * Appends the constructor body. + * + * @param builder the builder + * @param ctx the context + * @param builderTag the builder tag + */ + protected void appendCtorCodeBody(StringBuilder builder, + BodyContext ctx, + String builderTag) { + if (ctx.hasParent()) { + builder.append("\t\tsuper(b);\n"); + } + int i = 0; + for (String beanAttributeName : ctx.allAttributeNames()) { + TypedElementName method = ctx.allTypeInfos().get(i++); + builder.append("\t\tthis.").append(beanAttributeName).append(" = "); + + if (method.typeName().isList()) { + builder.append("Collections.unmodifiableList(new ") + .append(ctx.listType()).append("<>(b.").append(beanAttributeName).append("));\n"); + } else if (method.typeName().isMap()) { + builder.append("Collections.unmodifiableMap(new ") + .append(ctx.mapType()).append("<>(b.").append(beanAttributeName).append("));\n"); + } else if (method.typeName().isSet()) { + builder.append("Collections.unmodifiableSet(new ") + .append(ctx.setType()).append("<>(b.").append(beanAttributeName).append("));\n"); + } else { + builder.append("b.").append(beanAttributeName).append(";\n"); + } + } + } + private void appendHashCodeAndEquals(StringBuilder builder, BodyContext ctx) { if (ctx.doingConcreteType()) { @@ -1409,32 +1508,6 @@ private void appendDefaultValueAssignment(StringBuilder builder, } } - private void appendCtorCode(StringBuilder builder, - String ignoredBuilderTag, - BodyContext ctx) { - if (ctx.hasParent()) { - builder.append("\t\tsuper(b);\n"); - } - int i = 0; - for (String beanAttributeName : ctx.allAttributeNames()) { - TypedElementName method = ctx.allTypeInfos().get(i++); - builder.append("\t\tthis.").append(beanAttributeName).append(" = "); - - if (method.typeName().isList()) { - builder.append("Collections.unmodifiableList(new ") - .append(ctx.listType()).append("<>(b.").append(beanAttributeName).append("));\n"); - } else if (method.typeName().isMap()) { - builder.append("Collections.unmodifiableMap(new ") - .append(ctx.mapType()).append("<>(b.").append(beanAttributeName).append("));\n"); - } else if (method.typeName().isSet()) { - builder.append("Collections.unmodifiableSet(new ") - .append(ctx.setType()).append("<>(b.").append(beanAttributeName).append("));\n"); - } else { - builder.append("b.").append(beanAttributeName).append(";\n"); - } - } - } - private void appendOverridesOfDefaultValues(StringBuilder builder, BodyContext ctx) { boolean first = true; @@ -1504,7 +1577,7 @@ private String mapOf(String attrName, String typeDecl = "\"type\", " + typeName.name() + ".class"; if (!typeName.typeArguments().isEmpty()) { int pos = typeName.typeArguments().size() - 1; - typeDecl += ", \"componentType\", " + typeName.typeArguments().get(pos).name() + ".class"; + typeDecl += ", \"componentType\", " + normalize(typeName.typeArguments().get(pos).name()) + ".class"; } String key = (configuredOptions.isEmpty()) @@ -1543,6 +1616,10 @@ private String mapOf(String attrName, return result.toString(); } + private String normalize(String name) { + return name.equals("?") ? "Object" : name; + } + private String quotedTupleOf(String key, String val) { assert (Objects.nonNull(key)); diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java index 0b7fc795fc9..e8cc9e99d23 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java @@ -48,7 +48,7 @@ static void builderMethod(StringBuilder builder, builder.append("\t/**\n" + "\t * Creates a builder for this type.\n" + "\t *\n"); - builder.append("\t * @return A builder for {@link "); + builder.append("\t * @return a builder for {@link "); builder.append(ctx.typeInfo().typeName()); builder.append("}\n\t */\n"); } @@ -56,10 +56,10 @@ static void builderMethod(StringBuilder builder, static void toBuilderMethod(StringBuilder builder, BodyContext ctx) { builder.append("\t/**\n" - + "\t * Creates a builder for this type, initialized with the attributes from the values passed" - + ".\n\n"); + + "\t * Creates a builder for this type, initialized with the attributes from the values passed.\n" + + "\t *\n"); builder.append("\t * @param val the value to copy to initialize the builder attributes\n"); - builder.append("\t * @return A builder for {@link ").append(ctx.typeInfo().typeName()); + builder.append("\t * @return a builder for {@link ").append(ctx.typeInfo().typeName()); builder.append("}\n\t */\n"); } diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java index 516b5356b31..89c5cd247f8 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java @@ -26,7 +26,7 @@ final class GenerateMethod { private GenerateMethod() { } - static void builderMethods(StringBuilder builder, + static String builderMethods(StringBuilder builder, BodyContext ctx) { GenerateJavadoc.builderMethod(builder, ctx); builder.append("\tpublic static Builder"); @@ -40,6 +40,8 @@ static void builderMethods(StringBuilder builder, builder.append("\t\tObjects.requireNonNull(val);\n"); builder.append("\t\treturn builder().accept(val);\n"); builder.append("\t}\n\n"); + + return "public static Builder toBuilder({args})"; } static void stringToCharSetter(StringBuilder builder, @@ -60,7 +62,7 @@ static void stringToCharSetter(StringBuilder builder, static void internalMetaAttributes(StringBuilder builder) { GenerateJavadoc.internalMetaAttributes(builder); builder.append("\tpublic static Map> __metaAttributes() {\n" - + "\t\treturn META_PROPS;\n" + + "\t\treturn ").append(BodyContext.TAG_META_PROPS).append(";\n" + "\t}\n\n"); } diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitor.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java similarity index 97% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitor.java rename to pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java index 9494351394d..80bf74a439f 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitor.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java @@ -16,11 +16,11 @@ package io.helidon.pico.builder.processor.tools; -final class GenerateVisitor { - private GenerateVisitor() { +final class GenerateVisitorSupport { + private GenerateVisitorSupport() { } - static void appendAttributeVisitors(StringBuilder builder, + static void appendExtraInnerClasses(StringBuilder builder, BodyContext ctx) { if (ctx.doingConcreteType()) { return; diff --git a/pico/builder/tests/builder/pom.xml b/pico/builder/tests/builder/pom.xml index 4efc5f7ad57..d19a71fbbbd 100644 --- a/pico/builder/tests/builder/pom.xml +++ b/pico/builder/tests/builder/pom.xml @@ -47,12 +47,11 @@ io.helidon.pico.builder - helidon-pico-builder-processor - provided + helidon-pico-builder - io.helidon.pico.builder - helidon-pico-builder + io.helidon.pico.builder.config + helidon-pico-builder-config io.helidon.config diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java b/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java index fcd49976094..7d0bba9b188 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java +++ b/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java @@ -53,6 +53,13 @@ public interface ComplexCase extends MyConfigBean { */ Set> getSetOfLists(); + /** + * Used for testing. + * + * @return ignored, here for testing purposes only + */ + Class getClassType(); + /** * The Pico Builder will ignore {@code default} and {@code static} functions. * diff --git a/pico/builder/tests/builder/src/main/java/module-info.java b/pico/builder/tests/builder/src/main/java/module-info.java index fe7ebf18b7c..23b72f8123d 100644 --- a/pico/builder/tests/builder/src/main/java/module-info.java +++ b/pico/builder/tests/builder/src/main/java/module-info.java @@ -20,6 +20,7 @@ module io.helidon.pico.builder.test.builder { requires static com.fasterxml.jackson.annotation; requires static io.helidon.config.metadata; - requires io.helidon.pico.builder; + requires io.helidon.common; + requires io.helidon.pico.builder; } diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java b/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java index 1d2470e037f..168e458cfac 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java +++ b/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java @@ -40,10 +40,11 @@ void testIt() { .name("name") .mapOfKeyToConfigBeans(mapWithNull) .setOfLists(Collections.singleton(Collections.singletonList(null))) + .classType(Object.class) .build(); assertThat(val.toString(), equalTo("ComplexCase(name=name, enabled=false, port=8080, mapOfKeyToConfigBeans={key=null}, " - + "listOfConfigBeans=[], setOfLists=[[null]])")); + + "listOfConfigBeans=[], setOfLists=[[null]], classType=class java.lang.Object)")); } } diff --git a/pico/builder/tests/pom.xml b/pico/builder/tests/pom.xml index e1577ee98cd..72894e24189 100644 --- a/pico/builder/tests/pom.xml +++ b/pico/builder/tests/pom.xml @@ -36,6 +36,15 @@ Helidon Pico Builder Tests Project pom + + true + true + + true + true + true + + builder diff --git a/pico/pom.xml b/pico/pom.xml index 681bc471128..2f7242dbbfe 100644 --- a/pico/pom.xml +++ b/pico/pom.xml @@ -47,6 +47,7 @@ types builder + builder-config pico diff --git a/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java b/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java index 8ebaa76e328..e8893d8809f 100644 --- a/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java +++ b/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java @@ -126,7 +126,6 @@ public static DefaultTypeName createFromTypeName(String typeName) { return createFromTypeName(typeName.substring(10).trim()) .toBuilder() .wildcard(true) - .generic(true) .build(); } @@ -158,6 +157,18 @@ public static DefaultTypeName createFromTypeName(String typeName) { return create(packageName, className); } + /** + * Given a typeName X, will return an typeName of "? extends X". + * + * @param typeName the typeName + * @return the wildcard extension of the given typeName + */ + public static TypeName createExtendsTypeName(TypeName typeName) { + return toBuilder(typeName) + .wildcard(true) + .build(); + } + /** * Throws an exception if the provided type name is not fully qualified, having a package and class name representation. * @@ -325,13 +336,7 @@ protected Builder() { * @param val the typeName */ protected Builder(TypeName val) { - this.packageName = val.packageName(); - this.className = val.className(); - this.primitive = val.primitive(); - this.array = val.array(); - this.wildcard = val.wildcard(); - this.generic = val.generic(); - this.typeArguments.addAll(val.typeArguments()); + copyFrom(val); } /** @@ -346,6 +351,23 @@ public DefaultTypeName build() { return new DefaultTypeName(this); } + /** + * Copy from an existing typeName. + * + * @param val the typeName to copy + * @return the fluent builder + */ + protected Builder copyFrom(TypeName val) { + this.packageName = val.packageName(); + this.className = val.className(); + this.primitive = val.primitive(); + this.array = val.array(); + this.wildcard = val.wildcard(); + this.generic = val.generic(); + this.typeArguments.addAll(val.typeArguments()); + return this; + } + /** * Set the package name. * diff --git a/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java b/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java index fa76c112307..9a36366cba7 100644 --- a/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java +++ b/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java @@ -300,4 +300,12 @@ void builderOfType() { assertThat(objTypeName.className(), equalTo("Boolean")); } + @Test + void extendsTypeName() { + TypeName extendsName = DefaultTypeName.createExtendsTypeName(create(Map.class)); + assertThat(extendsName.fqName(), equalTo("? extends java.util.Map")); + assertThat(extendsName.declaredName(), equalTo("java.util.Map")); + assertThat(extendsName.name(), equalTo("java.util.Map")); + } + } From 22d198c148de9375cde91b791aca5c86f29a6f21 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Mon, 21 Nov 2022 17:40:23 -0500 Subject: [PATCH 02/36] checkstyle suppression, and javadoc fixups --- etc/checkstyle-suppressions.xml | 11 +- .../config/fakes/config/FakeClientAuth.java | 49 - .../config/FakeComponentTracingConfig.java | 223 ----- .../config/fakes/config/FakeKeyConfig.java | 839 ----------------- .../fakes/config/FakeKeystoreConfig.java | 132 --- .../fakes/config/FakePathTracingConfig.java | 179 ---- .../fakes/config/FakeRoutingConfig.java | 699 -------------- .../config/fakes/config/FakeServerConfig.java | 763 ---------------- .../fakes/config/FakeServerLifecycle.java | 38 - .../config/fakes/config/FakeSocketConfig.java | 849 ------------------ .../config/FakeSpanLogTracingConfig.java | 128 --- .../fakes/config/FakeSpanTracingConfig.java | 258 ------ .../fakes/config/FakeTraceableConfig.java | 56 -- .../config/fakes/config/FakeTracer.java | 103 --- .../fakes/config/FakeTracingConfig.java | 244 ----- .../fakes/config/FakeWebServerTlsConfig.java | 438 --------- .../config/fakes/config/SSLContextConfig.java | 201 ----- .../config/testsubjects/ClientConfig.java | 21 +- .../config/testsubjects/CommonConfig.java | 23 + .../config/testsubjects/ServerConfig.java | 13 + .../package-info.java} | 14 +- .../builder/config/fakes/FakeClientAuth.java | 0 .../fakes/FakeComponentTracingConfig.java | 0 .../builder/config/fakes/FakeKeyConfig.java | 0 .../config/fakes/FakeKeystoreConfig.java | 0 .../config/fakes/FakeNettyClientAuth.java | 0 .../config/fakes/FakePathTracingConfig.java | 0 .../config/fakes/FakeRoutingConfig.java | 0 .../config/fakes/FakeServerConfig.java | 0 .../config/fakes/FakeServerLifecycle.java | 0 .../config/fakes/FakeSocketConfig.java | 0 .../fakes/FakeSpanLogTracingConfig.java | 0 .../config/fakes/FakeSpanTracingConfig.java | 0 .../config/fakes/FakeTraceableConfig.java | 0 .../pico/builder/config/fakes/FakeTracer.java | 0 .../config/fakes/FakeTracingConfig.java | 0 .../builder/config/fakes/FakeWebServer.java | 0 .../config/fakes/FakeWebServerTlsConfig.java | 0 .../config/fakes/SSLContextConfig.java | 0 .../pico/builder/config/fakes/WebServer.java | 0 40 files changed, 69 insertions(+), 5212 deletions(-) delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java rename pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/{fakes/config/FakeNettyClientAuth.java => testsubjects/package-info.java} (78%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeTracer.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/WebServer.java (100%) diff --git a/etc/checkstyle-suppressions.xml b/etc/checkstyle-suppressions.xml index 4897aff7cb5..ffc6a4e56ea 100644 --- a/etc/checkstyle-suppressions.xml +++ b/etc/checkstyle-suppressions.xml @@ -77,5 +77,14 @@ - + + + + + + diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java deleted file mode 100644 index 1f6fb1a11a7..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java +++ /dev/null @@ -1,49 +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.pico.builder.config.fakes.config; - -/** - * Indicates whether the server requires authentication of tbe client by the certificate. - */ -public enum FakeClientAuth { - - /** - * Authentication is required. - */ - REQUIRE(FakeNettyClientAuth.REQUIRE), - - /** - * Authentication is optional. - */ - OPTIONAL(FakeNettyClientAuth.OPTIONAL), - - /** - * Authentication is not required. - */ - NONE(FakeNettyClientAuth.NONE); - - private final FakeNettyClientAuth clientAuth; - - FakeClientAuth(FakeNettyClientAuth clientAuth) { - this.clientAuth = clientAuth; - } - - FakeNettyClientAuth nettyClientAuth(){ - return clientAuth; - } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java deleted file mode 100644 index 182690407bc..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java +++ /dev/null @@ -1,223 +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.pico.builder.config.fakes.config; - -import java.util.Map; - -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka ComponentTracing. - */ -@ConfigBean -public interface FakeComponentTracingConfig extends FakeTraceableConfig { -// /** -// * Disabled component - all subsequent calls return disabled spans and logs. -// */ -// public static final ComponentTracingConfig DISABLED = ComponentTracingConfig.builder("disabled").enabled(false).build(); -// /** -// * Enabled component - all subsequent calls return enabled spans and logs. -// */ -// public static final ComponentTracingConfig ENABLED = ComponentTracingConfig.builder("enabled").build(); - -// /** -// * A new named component. -// * -// * @param name name of the component -// */ -// protected ComponentTracingConfig(String name) { -// super(name); -// } -// - -// /** -// * Merge configuration of two traced components. This enabled hierarchical configuration -// * with common, default configuration in one traced component and override in another. -// * -// * @param older the older configuration with "defaults" -// * @param newer the newer configuration to override defaults in older -// * @return merged component -// */ -// static ComponentTracingConfig merge(ComponentTracingConfig older, ComponentTracingConfig newer) { -// return new ComponentTracingConfig(newer.name()) { -// @Override -// public Optional getSpan(String spanName) { -// if (!enabled()) { -// return Optional.of(SpanTracingConfig.DISABLED); -// } -// -// Optional newSpan = newer.getSpan(spanName); -// Optional oldSpan = older.getSpan(spanName); -// -// // both configured -// if (newSpan.isPresent() && oldSpan.isPresent()) { -// return Optional.of(SpanTracingConfig.merge(oldSpan.get(), newSpan.get())); -// } -// -// // only newer -// if (newSpan.isPresent()) { -// return newSpan; -// } -// -// return oldSpan; -// } -// -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// }; -// } -// -// /** -// * Get a traced span configuration for a named span. -// * -// * @param spanName name of the span in this component -// * @return configuration of that span if present -// */ -// protected abstract Optional getSpan(String spanName); -// -// /** -// * Get a traced span configuration for a named span. -// * -// * @param spanName name of a span in this component -// * @return configuration of the span, or enabled configuration if not configured -// * @see #span(String, boolean) -// */ -// public SpanTracingConfig span(String spanName) { -// return span(spanName, true); -// } - - @Singular("span") // Builder::addSpan(String span, FakeSpanLogTracingConfigBean val), Impl::getSpan(String span), etc. - Map spanLogMap(); - -// -// /** -// * Get a traced span configuration for a named span. -// * -// * @param spanName name of a span in this component -// * @param enabledByDefault whether the result is enabled if a configuration is not present -// * @return configuration of the span, or a span configuration enabled or disabled depending on {@code enabledByDefault} if -// * not configured -// */ -// public SpanTracingConfig span(String spanName, boolean enabledByDefault) { -// if (enabled()) { -// return getSpan(spanName).orElseGet(() -> enabledByDefault ? SpanTracingConfig.ENABLED : SpanTracingConfig.DISABLED); -// } -// -// return SpanTracingConfig.DISABLED; -// } -// -// /** -// * Fluent API builder for traced component. -// * -// * @param name the name of the component -// * @return a new builder instance -// */ -// public static Builder builder(String name) { -// return new Builder(name); -// } -// -// /** -// * Create a new traced component configuration from {@link Config}. -// * -// * @param name name of the component -// * @param config config for a new component -// * @return a new traced component configuration -// */ -// public static ComponentTracingConfig create(String name, Config config) { -// return builder(name) -// .config(config) -// .build(); -// } -// -// /** -// * Fluent API builder for {@link ComponentTracingConfig}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final Map tracedSpans = new HashMap<>(); -// private Optional enabled = Optional.empty(); -// private final String name; -// -// private Builder(String name) { -// this.name = name; -// } -// -// @Override -// public ComponentTracingConfig build() { -// // immutability -// final Optional finalEnabled = enabled; -// final Map finalSpans = new HashMap<>(tracedSpans); -// return new ComponentTracingConfig(name) { -// @Override -// public Optional getSpan(String spanName) { -// if (enabled.orElse(true)) { -// return Optional.ofNullable(finalSpans.get(spanName)); -// } else { -// return Optional.of(SpanTracingConfig.DISABLED); -// } -// } -// -// @Override -// public Optional isEnabled() { -// return finalEnabled; -// } -// }; -// } -// -// /** -// * Update this builder from {@link io.helidon.config.Config}. -// * -// * @param config configuration of a traced component -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// config.get("spans").asNodeList().ifPresent(spanConfigList -> { -// spanConfigList.forEach(spanConfig -> { -// // span name is mandatory -// addSpan(SpanTracingConfig.create(spanConfig.get("name").asString().get(), spanConfig)); -// }); -// }); -// return this; -// } -// -// /** -// * Add a new traced span configuration. -// * -// * @param span configuration of a traced span -// * @return updated builder instance -// */ -// public Builder addSpan(SpanTracingConfig span) { -// this.tracedSpans.put(span.name(), span); -// return this; -// } -// -// /** -// * Configure whether this component is enabled or disabled. -// * -// * @param enabled if disabled, all spans and logs will be disabled -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java deleted file mode 100644 index 3adb14006fc..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java +++ /dev/null @@ -1,839 +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.pico.builder.config.fakes.config; - -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.Optional; - -import io.helidon.pico.builder.Builder; - -/** - * aka KeyConfig. - * - */ -@Builder -public interface FakeKeyConfig { - - // /*private static final*/ String DEFAULT_PRIVATE_KEY_ALIAS = "1"; -// /*private static final*/ char[] EMPTY_CHARS = new char[0]; - -// private static final Logger LOGGER = Logger.getLogger(FakeKeyConfigBean.class.getName()); -// -// private final PrivateKey privateKey; -// private final PublicKey publicKey; -// private final X509Certificate publicCert; -// private final List certChain = new LinkedList<>(); -// private final List certificates = new LinkedList<>(); -// -// private FakeKeyConfigBean(PrivateKey privateKey, -// PublicKey publicKey, -// X509Certificate publicCert, -// Collection certChain, -// Collection certificates) { -// -// this.privateKey = privateKey; -// this.publicKey = publicKey; -// this.publicCert = publicCert; -// this.certChain.addAll(certChain); -// this.certificates.addAll(certificates); -// } -// -// /** -// * Load key config from config. -// * -// * @param config config instance located at keys configuration (expects "keystore-path" child) -// * @return KeyConfig loaded from config -// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured -// */ -// public static FakeKeyConfigBean create(Config config) throws PkiException { -// try { -// return fullBuilder().config(config).build(); -// } catch (ResourceException e) { -// throw new PkiException("Failed to load from config", e); -// } -// } -// -// /** -// * Creates a new builder to configure instance. -// * -// * @return builder instance -// */ -// public static Builder fullBuilder() { -// return new Builder(); -// } -// -// /** -// * Build this instance from PEM files (usually a pair of private key and certificate chain). -// * Call {@link PemBuilder#build()} to build the instance. -// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. -// * -// * @return builder for PEM files -// */ -// public static PemBuilder pemBuilder() { -// return new PemBuilder(); -// } -// -// /** -// * Build this instance from a java keystore (such as PKCS12 keystore). -// * Call {@link KeystoreBuilder#build()} to build the instance. -// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. -// * -// * @return builder for Keystore -// */ -// public static KeystoreBuilder keystoreBuilder() { -// return new KeystoreBuilder(); -// } -// - /** - * The public key of this config if configured. - * - * @return the public key of this config or empty if not configured - */ - /*public*/ Optional publicKey(); -// { -// return Optional.ofNullable(publicKey); -// } - - /** - * The private key of this config if configured. - * - * @return the private key of this config or empty if not configured - */ - /*public*/ Optional privateKey(); -// { -// return Optional.ofNullable(privateKey); -// } - - /** - * The public X.509 Certificate if configured. - * - * @return the public certificate of this config or empty if not configured - */ - /*public*/ Optional publicCert(); -// { -// return Optional.ofNullable(publicCert); -// } - - /** - * The X.509 Certificate Chain. - * - * @return the certificate chain or empty list if not configured - */ - /*public*/ List certChain(); -// { -// return Collections.unmodifiableList(certChain); -// } - - /** - * The X.509 Certificates. - * - * @return the certificates configured or empty list if none configured - */ - /*public*/ List certs(); -// { -// return Collections.unmodifiableList(certificates); -// } - - -// public DefaultFakeConfigBean.Builder config(Config config) { -// Config keystoreConfig = config.get("keystore"); -// -// // the actual resource (file, classpath) with the bytes of the keystore -// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); -// -// // type of keystore -// keystoreConfig.get("type") -// .asString() -// .ifPresent(this::keystoreType); -// // password of the keystore -// keystoreConfig.get("passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keystorePassphrase); -// // private key alias -// keystoreConfig.get("key.alias") -// .asString() -// .ifPresent(this::keyAlias); -// // private key password -// keystoreConfig.get("key.passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keyPassphrase); -// keystoreConfig.get("cert.alias") -// .asString() -// .ifPresent(this::certAlias); -// keystoreConfig.get("cert-chain.alias") -// .asString() -// .ifPresent(this::certChainAlias); -// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) -// keystoreConfig.get("trust-store") -// .asBoolean() -// .ifPresent(this::trustStore); -// -// return this; -// } - - -// /** -// * Fluent API builder for {@link FakeKeyConfigBean}. -// * Call {@link #build()} to create an instance. -// * -// * The keys may be loaded from multiple possible sources. -// * -// * @see FakeKeyConfigBean#keystoreBuilder() -// * @see FakeKeyConfigBean#pemBuilder() -// * @see FakeKeyConfigBean#fullBuilder() -// */ -// @Configured -// public static class Builder implements io.helidon.common.Builder { -// private PrivateKey explicitPrivateKey; -// private PublicKey explicitPublicKey; -// private X509Certificate explicitPublicCert; -// private final List explicitCertChain = new LinkedList<>(); -// private final List explicitCertificates = new LinkedList<>(); -// -// /** -// * Build a new instance of the configuration based on this builder. -// * -// * @return instance from this builder -// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured -// */ -// @Override -// public FakeKeyConfigBean build() throws PkiException { -// PrivateKey privateKey = this.explicitPrivateKey; -// PublicKey publicKey = this.explicitPublicKey; -// X509Certificate publicCert = this.explicitPublicCert; -// List certChain = new LinkedList<>(explicitCertChain); -// List certificates = new LinkedList<>(explicitCertificates); -// -// // fix public key if cert is provided -// if (null == publicKey && null != publicCert) { -// publicKey = publicCert.getPublicKey(); -// } -// -// return new FakeKeyConfigBean(privateKey, publicKey, publicCert, certChain, certificates); -// } -// -// /** -// * Configure a private key instance (rather then keystore and alias). -// * -// * @param privateKey private key instance -// * @return updated builder instance -// */ -// public Builder privateKey(PrivateKey privateKey) { -// this.explicitPrivateKey = privateKey; -// return this; -// } -// -// /** -// * Configure a public key instance (rather then keystore and certificate alias). -// * -// * @param publicKey private key instance -// * @return updated builder instance -// */ -// public Builder publicKey(PublicKey publicKey) { -// this.explicitPublicKey = publicKey; -// return this; -// } -// -// /** -// * Configure an X.509 certificate instance for public key certificate. -// * -// * @param certificate certificate instance -// * @return updated builder instance -// */ -// public Builder publicKeyCert(X509Certificate certificate) { -// this.explicitPublicCert = certificate; -// return this; -// } -// -// /** -// * Add an X.509 certificate instance to the end of certification chain. -// * -// * @param certificate certificate to add to certification path -// * @return updated builder instance -// */ -// public Builder addCertChain(X509Certificate certificate) { -// this.explicitCertChain.add(certificate); -// return this; -// } -// -// /** -// * Add a certificate to the list of certificates, used e.g. in a trust store. -// * -// * @param certificate X.509 certificate to trust -// * @return updated builder instance -// */ -// public Builder addCert(X509Certificate certificate) { -// this.explicitCertificates.add(certificate); -// return this; -// } -// -// /** -// * Update this builder with information from a pem builder. -// * -// * @param builder builder obtained from {@link FakeKeyConfigBean#pemBuilder()} -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "pem") -// public Builder updateWith(PemBuilder builder) { -// builder.updateBuilder(this); -// return this; -// } -// -// /** -// * Update this builder with information from a keystore builder. -// * -// * @param builder builder obtained from {@link FakeKeyConfigBean#keystoreBuilder()} ()} -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "keystore") -// public Builder updateWith(KeystoreBuilder builder) { -// builder.updateBuilder(this); -// return this; -// } -// -// /** -// * Updated this builder instance from configuration. -// * Keys configured will override existing fields in this builder, others will be left intact. -// * If certification path is already defined, configuration based cert-path will be added. -// * -// * @param config configuration to update this builder from -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// updateWith(pemBuilder().config(config)); -// updateWith(keystoreBuilder().config(config)); -// -// return this; -// } -// } -// -// /** -// * Builder for resources from a java keystore (PKCS12, JKS etc.). Obtain an instance through {@link -// * FakeKeyConfigBean#keystoreBuilder()}. -// */ -// @Configured(ignoreBuildMethod = true) -// public static final class KeystoreBuilder implements io.helidon.common.Builder { -// private static final String DEFAULT_KEYSTORE_TYPE = "PKCS12"; -// -// private String keystoreType = DEFAULT_KEYSTORE_TYPE; -// private char[] keystorePassphrase = EMPTY_CHARS; -// private char[] keyPassphrase = null; -// private String keyAlias; -// private String certAlias; -// private String certChainAlias; -// private boolean addAllCertificates; -// private final List certificateAliases = new LinkedList<>(); -// private final StreamHolder keystoreStream = new StreamHolder("keystore"); -// -// private KeystoreBuilder() { -// } -// -// /** -// * If you want to build a trust store, call this method to add all -// * certificates present in the keystore to certificate list. -// * -// * @return updated builder instance -// */ -// @ConfiguredOption(type = Boolean.class, value = "false") -// public KeystoreBuilder trustStore() { -// return trustStore(true); -// } -// -// private KeystoreBuilder trustStore(boolean isTrustStore) { -// this.addAllCertificates = isTrustStore; -// return this; -// } -// -// /** -// * Add an alias to list of aliases used to generate a trusted set of certificates. -// * -// * @param alias alias of a certificate -// * @return updated builder instance -// */ -// public KeystoreBuilder addCertAlias(String alias) { -// certificateAliases.add(alias); -// return this; -// } -// -// /** -// * Keystore resource definition. -// * -// * @param keystore keystore resource, from file path, classpath, URL etc. -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "resource", required = true) -// public KeystoreBuilder keystore(Resource keystore) { -// this.keystoreStream.stream(keystore); -// return this; -// } -// -// /** -// * Set type of keystore. -// * Defaults to "PKCS12", expected are other keystore types supported by java then can store keys under aliases. -// * -// * @param keystoreType keystore type to load the key -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "type", value = "PKCS12") -// public KeystoreBuilder keystoreType(String keystoreType) { -// this.keystoreType = keystoreType; -// return this; -// } -// -// /** -// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). -// * -// * @param keystorePassphrase keystore pass-phrase -// * @return updated builder instance -// */ -// public KeystoreBuilder keystorePassphrase(char[] keystorePassphrase) { -// this.keystorePassphrase = Arrays.copyOf(keystorePassphrase, keystorePassphrase.length); -// -// return this; -// } -// -// /** -// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). -// * -// * @param keystorePassword keystore password to use, calls {@link #keystorePassphrase(char[])} -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "passphrase") -// public KeystoreBuilder keystorePassphrase(String keystorePassword) { -// return keystorePassphrase(keystorePassword.toCharArray()); -// } -// -// /** -// * Alias of the private key in the keystore. -// * -// * @param keyAlias alias of the key in the keystore -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.alias", value = "1") -// public KeystoreBuilder keyAlias(String keyAlias) { -// this.keyAlias = keyAlias; -// return this; -// } -// -// /** -// * Alias of X.509 certificate of public key. -// * Used to load both the certificate and public key. -// * -// * @param alias alias under which the certificate is stored in the keystore -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "cert.alias") -// public KeystoreBuilder certAlias(String alias) { -// this.certAlias = alias; -// return this; -// } -// -// /** -// * Alias of an X.509 chain. -// * -// * @param alias alias of certificate chain in the keystore -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "cert-chain.alias") -// public KeystoreBuilder certChainAlias(String alias) { -// this.certChainAlias = alias; -// return this; -// } -// -// /** -// * 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. -// * -// * @param privateKeyPassphrase pass-phrase of the key -// * @return updated builder instance -// */ -// public KeystoreBuilder keyPassphrase(char[] privateKeyPassphrase) { -// this.keyPassphrase = Arrays.copyOf(privateKeyPassphrase, privateKeyPassphrase.length); -// -// return this; -// } -// -// /** -// * 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. -// * -// * @param privateKeyPassphrase pass-phrase of the key -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.passphrase") -// public KeystoreBuilder keyPassphrase(String privateKeyPassphrase) { -// return keyPassphrase(privateKeyPassphrase.toCharArray()); -// } -// -// /** -// * Create an instance of {@link FakeKeyConfigBean} based on this builder. -// * -// * @return new key config based on a keystore -// */ -// @Override -// public FakeKeyConfigBean build() { -// return toFullBuilder().build(); -// } -// -// /** -// * Create a builder for {@link FakeKeyConfigBean} from this keystore builder. This allows you to enhance the config -// * with additional (explicit) fields. -// * -// * @return builder of {@link FakeKeyConfigBean} -// */ -// public Builder toFullBuilder() { -// return updateBuilder(FakeKeyConfigBean.fullBuilder()); -// } -// - -// private Builder updateBuilder(Builder builder) { -// if (keystoreStream.isSet()) { -// if (null == keyPassphrase) { -// keyPassphrase = keystorePassphrase; -// } -// KeyStore keyStore; -// -// try { -// keyStore = PkiUtil.loadKeystore(keystoreType, -// keystoreStream.stream(), -// keystorePassphrase, -// keystoreStream.message()); -// } finally { -// keystoreStream.closeStream(); -// } -// -// // attempt to read private key -// boolean guessing = false; -// if (null == keyAlias) { -// keyAlias = DEFAULT_PRIVATE_KEY_ALIAS; -// guessing = true; -// } -// try { -// builder.privateKey(PkiUtil.loadPrivateKey(keyStore, keyAlias, keyPassphrase)); -// } catch (Exception e) { -// if (guessing) { -// LOGGER.log(Level.FINEST, "Failed to read private key from default alias", e); -// } else { -// throw e; -// } -// } -// -// List certChain = null; -// if (null == certChainAlias) { -// guessing = true; -// // by default, cert chain uses the same alias as private key -// certChainAlias = keyAlias; -// } else { -// guessing = false; -// } -// -// if (null != certChainAlias) { -// try { -// certChain = PkiUtil.loadCertChain(keyStore, certChainAlias); -// certChain.forEach(builder::addCertChain); -// } catch (Exception e) { -// if (guessing) { -// LOGGER.log(Level.FINEST, "Failed to certificate chain from alias \"" + certChainAlias + "\"", e); -// } else { -// throw e; -// } -// } -// } -// -// if (null == certAlias) { -// // no explicit public key certificate, just load it from cert chain if present -// if (null != certChain && !certChain.isEmpty()) { -// builder.publicKeyCert(certChain.get(0)); -// } -// } else { -// builder.publicKeyCert(PkiUtil.loadCertificate(keyStore, certAlias)); -// } -// -// if (addAllCertificates) { -// PkiUtil.loadCertificates(keyStore).forEach(builder::addCert); -// } else { -// certificateAliases.forEach(it -> builder.addCert(PkiUtil.loadCertificate(keyStore, it))); -// } -// } -// return builder; -// } -// -// /** -// * Update this builder from configuration. -// * The following keys are expected under key {@code keystore}: -// *

    -// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • -// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • -// *
  • {@code passphrase}: passphrase of keystore, if required
  • -// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • -// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • -// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • -// *
  • {@code cert-chain.alias}: alias of certificate chain
  • -// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • -// *
-// * -// * @param config configuration instance -// * @return updated builder instance -// */ -// public KeystoreBuilder config(Config config) { -// Config keystoreConfig = config.get("keystore"); -// -// // the actual resource (file, classpath) with the bytes of the keystore -// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); -// -// // type of keystore -// keystoreConfig.get("type") -// .asString() -// .ifPresent(this::keystoreType); -// // password of the keystore -// keystoreConfig.get("passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keystorePassphrase); -// // private key alias -// keystoreConfig.get("key.alias") -// .asString() -// .ifPresent(this::keyAlias); -// // private key password -// keystoreConfig.get("key.passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keyPassphrase); -// keystoreConfig.get("cert.alias") -// .asString() -// .ifPresent(this::certAlias); -// keystoreConfig.get("cert-chain.alias") -// .asString() -// .ifPresent(this::certChainAlias); -// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) -// keystoreConfig.get("trust-store") -// .asBoolean() -// .ifPresent(this::trustStore); -// -// return this; -// } -// } -// - -// /** -// * Builder for PEM files - accepts private key and certificate chain. Obtain an instance through {@link -// * FakeKeyConfigBean#pemBuilder()}. -// * -// * If you have "standard" linux/unix private key, you must run " -// * {@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa.p8}" on it to work with this builder for password protected -// * file; or "{@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa_nocrypt.p8 -nocrypt}" for unprotected file. -// * -// * The only supported format is PKCS#8. If you have a different format, you must to transform it to PKCS8 PEM format (to -// * use this builder), or to PKCS#12 keystore format (and use {@link KeystoreBuilder}). -// */ -// @Configured(ignoreBuildMethod = true) -// public static final class PemBuilder implements io.helidon.common.Builder { -// private final StreamHolder privateKeyStream = new StreamHolder("privateKey"); -// private final StreamHolder publicKeyStream = new StreamHolder("publicKey"); -// private final StreamHolder certChainStream = new StreamHolder("certChain"); -// private final StreamHolder certificateStream = new StreamHolder("certificate"); -// private char[] pemKeyPassphrase; -// -// private PemBuilder() { -// } -// -// /** -// * Read a private key from PEM format from a resource definition. -// * -// * @param resource key resource (file, classpath, URL etc.) -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.resource") -// public PemBuilder key(Resource resource) { -// privateKeyStream.stream(resource); -// return this; -// } -// -// /** -// * Read a public key from PEM format from a resource definition. -// * -// * @param resource key resource (file, classpath, URL etc.) -// * @return updated builder instance -// */ -// public PemBuilder publicKey(Resource resource) { -// publicKeyStream.stream(resource); -// return this; -// } -// -// /** -// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to -// * decrypt it. -// * -// * @param passphrase passphrase used to encrypt the private key -// * @return updated builder instance -// */ -// public PemBuilder keyPassphrase(char[] passphrase) { -// this.pemKeyPassphrase = Arrays.copyOf(passphrase, passphrase.length); -// -// return this; -// } -// -// /** -// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to -// * decrypt it. -// * -// * @param passphrase passphrase used to encrypt the private key -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.passphrase") -// public PemBuilder keyPassphrase(String passphrase) { -// return keyPassphrase(passphrase.toCharArray()); -// } -// -// /** -// * Load certificate chain from PEM resource. -// * -// * @param resource resource (e.g. classpath, file path, URL etc.) -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "cert-chain.resource") -// public PemBuilder certChain(Resource resource) { -// certChainStream.stream(resource); -// return this; -// } -// -// /** -// * Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. -// * -// * @param resource key resource (file, classpath, URL etc.) -// * @return updated builder instance -// */ -// public PemBuilder certificates(Resource resource) { -// certificateStream.stream(resource); -// return this; -// } -// -// /** -// * Build {@link FakeKeyConfigBean} based on information from PEM files only. -// * -// * @return new instance configured from this builder -// */ -// @Override -// public FakeKeyConfigBean build() { -// return toFullBuilder().build(); -// } -// -// /** -// * Get a builder filled from this builder to add additional information (such as public key from certificate etc.). -// * -// * @return builder for {@link FakeKeyConfigBean} -// */ -// public Builder toFullBuilder() { -// return updateBuilder(FakeKeyConfigBean.fullBuilder()); -// } -// -// private Builder updateBuilder(Builder builder) { -// if (privateKeyStream.isSet()) { -// builder.privateKey(PemReader.readPrivateKey(privateKeyStream.stream(), pemKeyPassphrase)); -// } -// if (publicKeyStream.isSet()) { -// builder.publicKey(PemReader.readPublicKey(publicKeyStream.stream())); -// } -// -// if (certChainStream.isSet()) { -// List chain = PemReader.readCertificates(certChainStream.stream()); -// chain.forEach(builder::addCertChain); -// if (!chain.isEmpty()) { -// builder.publicKeyCert(chain.get(0)); -// } -// } -// -// if (certificateStream.isSet()) { -// PemReader.readCertificates(certificateStream.stream()).forEach(builder::addCert); -// } -// -// return builder; -// } -// -// /** -// * Update this builder from configuration. -// * Expected keys: -// *
    -// *
  • pem-key-path - path to PEM private key file (PKCS#8 format)
  • -// *
  • pem-key-resource-path - path to resource on classpath
  • -// *
  • pem-key-passphrase - passphrase of private key if encrypted
  • -// *
  • pem-cert-chain-path - path to certificate chain PEM file
  • -// *
  • pem-cert-chain-resource-path - path to resource on classpath
  • -// *
-// * -// * @param config configuration to update builder from -// * @return updated builder instance -// */ -// public PemBuilder config(Config config) { -// Config pemConfig = config.get("pem"); -// pemConfig.get("key.resource").as(Resource::create).ifPresent(this::key); -// pemConfig.get("key.passphrase").asString().map(String::toCharArray).ifPresent(this::keyPassphrase); -// pemConfig.get("cert-chain.resource").as(Resource::create).ifPresent(this::certChain); -// pemConfig.get("certificates.resource").as(Resource::create).ifPresent(this::certificates); -// return this; -// } -// } -// -// private static final class StreamHolder { -// private final String baseMessage; -// private InputStream inputStream; -// private String message; -// -// private StreamHolder(String message) { -// this.baseMessage = message; -// this.message = message; -// } -// -// private boolean isSet() { -// return inputStream != null; -// } -// -// private void stream(Resource resource) { -// closeStream(); -// Objects.requireNonNull(resource, "Resource for \"" + message + "\" must not be null"); -// -// this.inputStream = resource.stream(); -// this.message = message + ":" + resource.sourceType() + ":" + resource.location(); -// } -// -// private InputStream stream() { -// return inputStream; -// } -// -// private String message() { -// return message; -// } -// -// private void closeStream() { -// if (null != inputStream) { -// try { -// inputStream.close(); -// } catch (IOException e) { -// LOGGER.log(Level.WARNING, "Failed to close input stream: " + message, e); -// } -// } -// message = baseMessage; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java deleted file mode 100644 index 563db6276a3..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java +++ /dev/null @@ -1,132 +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.pico.builder.config.fakes.config; - -import java.util.List; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka KeyConfig.Keystore.Builder - */ -@ConfigBean -public interface FakeKeystoreConfig { - - String DEFAULT_KEYSTORE_TYPE = "PKCS12"; - -// private final StreamHolder keystoreStream = new StreamHolder("keystore"); - -// default FakeKeystoreConfigBean trustStore() { -// return trustStore(true); -// } - - @ConfiguredOption(key = "trust-store") - boolean trustStore(); - -// /** -// * Keystore resource definition. -// * -// * @param keystore keystore resource, from file path, classpath, URL etc. -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "resource", required = true) -// public KeystoreBuilder keystore(Resource keystore) { -// this.keystoreStream.stream(keystore); -// return this; -// } -// default DefaultFakeKeystoreConfigBean.Builder keystore(Resource keystore) { -// -// } - - @ConfiguredOption(key = "type", value = DEFAULT_KEYSTORE_TYPE) - String keystoreType(); - - @ConfiguredOption(key = "passphrase") - char[] keystorePassphrase(); - - @ConfiguredOption(key = "key.alias", value = "1") - String keyAlias(); - - @ConfiguredOption(key = "key.passphrase") - char[] keyPassphrase(); - - @ConfiguredOption(key = "cert.alias") - @Singular("certAlias") - List certAliases(); - - @ConfiguredOption(key = "cert-chain.alias") - String certChainAlias(); - - -// /** -// * Update this builder from configuration. -// * The following keys are expected under key {@code keystore}: -// *
    -// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • -// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • -// *
  • {@code passphrase}: passphrase of keystore, if required
  • -// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • -// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • -// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • -// *
  • {@code cert-chain.alias}: alias of certificate chain
  • -// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • -// *
-// * -// * @param config configuration instance -// * @return updated builder instance -// */ -// public KeystoreBuilder config(Config config) { -// Config keystoreConfig = config.get("keystore"); -// -// // the actual resource (file, classpath) with the bytes of the keystore -// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); -// -// // type of keystore -// keystoreConfig.get("type") -// .asString() -// .ifPresent(this::keystoreType); -// // password of the keystore -// keystoreConfig.get("passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keystorePassphrase); -// // private key alias -// keystoreConfig.get("key.alias") -// .asString() -// .ifPresent(this::keyAlias); -// // private key password -// keystoreConfig.get("key.passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keyPassphrase); -// keystoreConfig.get("cert.alias") -// .asString() -// .ifPresent(this::certAlias); -// keystoreConfig.get("cert-chain.alias") -// .asString() -// .ifPresent(this::certChainAlias); -// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) -// keystoreConfig.get("trust-store") -// .asBoolean() -// .ifPresent(this::trustStore); -// -// return this; -// } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java deleted file mode 100644 index 6a8f321ae6d..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java +++ /dev/null @@ -1,179 +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.pico.builder.config.fakes.config; - -import java.util.List; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka PathTracing. - * - * Traced system configuration for web server for a specific path. - */ -@ConfigBean -public interface FakePathTracingConfig { -// /** -// * Create a new traced path configuration from {@link io.helidon.config.Config}. -// * @param config config of a path -// * @return traced path configuration -// */ -// static FakePathTracingConfigBean create(Config config) { -// return builder().config(config).build(); -// } -// -// /** -// * Create a new builder to configure traced path configuration. -// * -// * @return a new builder instance -// */ -// static Builder builder() { -// return new Builder(); -// } - - /** - * Path this configuration should configure. - * - * @return path on the web server - */ - String path(); - - /** - * Method(s) this configuration should be valid for. This can be used to restrict the configuration - * only to specific HTTP methods (such as {@code GET} or {@code POST}). - * - * @return list of methods, if empty, this configuration is valid for any method - */ - @Singular("method") // Builder::addMethod(String method); - List methods(); - -// /** -// * Associated configuration of tracing valid for the configured path and (possibly) methods. -// * -// * @return traced system configuration -// */ - @ConfiguredOption(required = true) - FakeTracingConfig tracedConfig(); - -// Optional tracedConfig(); - - -// /** -// * Fluent API builder for {@link FakePathTracingConfigBean}. -// */ -// final class Builder implements io.helidon.common.Builder { -// private final List methods = new LinkedList<>(); -// private String path; -// private TracingConfig tracedConfig; -// -// private Builder() { -// } -// -// @Override -// public FakePathTracingConfigBean build() { -// // immutable -// final String finalPath = path; -// final List finalMethods = new LinkedList<>(methods); -// final TracingConfig finalTracingConfig = tracedConfig; -// -// return new FakePathTracingConfigBean() { -// @Override -// public String path() { -// return finalPath; -// } -// -// @Override -// public List methods() { -// return finalMethods; -// } -// -// @Override -// public TracingConfig tracedConfig() { -// return finalTracingConfig; -// } -// -// @Override -// public String toString() { -// return path + "(" + finalMethods + "): " + finalTracingConfig; -// } -// }; -// } -// -// /** -// * Update this builder from provided {@link io.helidon.config.Config}. -// * -// * @param config config to update this builder from -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// path(config.get("path").asString().get()); -// List methods = config.get("methods").asList(String.class).orElse(null); -// if (null != methods) { -// methods(methods); -// } -// tracingConfig(TracingConfig.create(config)); -// -// return this; -// } -// -// /** -// * Path to register the traced configuration on. -// * -// * @param path path as understood by {@link io.helidon.webserver.Routing.Builder} of web server -// * @return updated builder instance -// */ -// public Builder path(String path) { -// this.path = path; -// return this; -// } -// -// /** -// * HTTP methods to restrict registration of this configuration on web server. -// * @param methods list of methods to use, empty means all methods -// * @return updated builder instance -// */ -// public Builder methods(List methods) { -// this.methods.clear(); -// this.methods.addAll(methods); -// return this; -// } -// -// /** -// * Add a new HTTP method to restrict this configuration for. -// * -// * @param method method to add to the list of supported methods -// * @return updated builder instance -// */ -// public Builder addMethod(String method) { -// this.methods.add(method); -// return this; -// } -// -// /** -// * Configuration of a traced system to use on this path and possibly method(s). -// * -// * @param tracedConfig configuration of components, spans and span logs -// * @return updated builder instance -// */ -// public Builder tracingConfig(TracingConfig tracedConfig) { -// this.tracedConfig = tracedConfig; -// return this; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java deleted file mode 100644 index 502b41fdec1..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java +++ /dev/null @@ -1,699 +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.pico.builder.config.fakes.config; - -/* - * 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. - */ - -/** - * aka Routing. - * - * an annotation to get something discovered (i.e., @CustomConfigBean?) - * - * Routing represents composition of HTTP request-response handlers with routing rules. - * It is a cornerstone of the {@link io.helidon.pico.config.fake.helidon.WebServer}. - */ -public interface FakeRoutingConfig extends FakeServerLifecycle { - -// void route(BareRequest bareRequest, BareResponse bareResponse); -// -// /** -// * Creates new instance of {@link Builder routing builder}. -// * -// * @return a new instance -// */ -// static Builder builder() { -// return new Builder(); -// } -// -// /** -// * An API to define HTTP request routing rules. -// * -// * @see Builder -// */ -// interface Rules { -// /** -// * Configuration of tracing for this routing. -// * The configuration may control whether to log specific components, -// * spans and span logs, either globally, or for a specific path and method combinations. -// * -// * @param webTracingConfig WebServer tracing configuration -// * @return Updated routing configuration -// */ -// Rules register(WebTracingConfig webTracingConfig); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param services services to register -// * @return Updated routing configuration -// */ -// Rules register(Service... services); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param serviceBuilders service builder to register; they will be built as a first step of this -// * method execution -// * @return Updated routing configuration -// */ -// @SuppressWarnings("unchecked") -// Rules register(Supplier... serviceBuilders); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param services services to register -// * @return Updated routing configuration -// */ -// Rules register(String pathPattern, Service... services); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param serviceBuilders service builder to register; they will be built as a first step of this -// * method execution -// * @return an updated routing configuration -// */ -// @SuppressWarnings("unchecked") -// Rules register(String pathPattern, Supplier... serviceBuilders); -// -// /** -// * Routes all GET requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules get(Handler... requestHandlers); -// -// /** -// * Routes GET requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules get(String pathPattern, Handler... requestHandlers); -// -// /** -// * Add a route. This allows also protocol version specific routing. -// * -// * @param route route to add -// * @return updated rules -// */ -// Rules route(HttpRoute route); -// -// /** -// * Routes GET requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules get(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all PUT requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules put(Handler... requestHandlers); -// -// /** -// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules put(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for a registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules put(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all POST requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules post(Handler... requestHandlers); -// -// /** -// * Routes POST requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules post(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes POST requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules post(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all RFC 5789 PATCH requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules patch(Handler... requestHandlers); -// -// /** -// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules patch(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules patch(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all DELETE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules delete(Handler... requestHandlers); -// -// /** -// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules delete(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules delete(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all OPTIONS requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules options(Handler... requestHandlers); -// -// /** -// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules options(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules options(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all HEAD requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules head(Handler... requestHandlers); -// -// /** -// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules head(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules head(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all TRACE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules trace(Handler... requestHandlers); -// -// /** -// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules trace(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules trace(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules any(Handler... requestHandlers); -// -// /** -// * Routes all requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules any(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes all requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules any(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes requests any specified method to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param methods HTTP methods -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules anyOf(Iterable methods, Handler... requestHandlers); -// -// /** -// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param methods HTTP methods -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules anyOf(Iterable methods, String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param methods HTTP methods -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules anyOf(Iterable methods, PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Registers callback on created new {@link WebServer} instance with this routing. -// * -// * @param webServerConsumer a WebServer creation callback -// * @return updated routing configuration -// */ -// Rules onNewWebServer(Consumer webServerConsumer); -// } -// -// /** -// * A {@link Routing} builder. -// */ -// class Builder implements Rules, io.helidon.common.Builder { -// -// private final RouteListRoutingRules delegate = new RouteListRoutingRules(); -// private final List> errorHandlerRecords = new ArrayList<>(); -// private boolean tracingRegistered; -// -// /** -// * Creates new instance. -// */ -// private Builder() { -// } -// -// // --------------- ROUTING API -// -// @Override -// public Builder register(WebTracingConfig webTracingConfig) { -// this.tracingRegistered = true; -// delegate.register(webTracingConfig); -// return this; -// } -// -// @Override -// @SuppressWarnings("unchecked") -// public Builder register(Supplier... serviceBuilders) { -// delegate.register(serviceBuilders); -// return this; -// } -// -// @Override -// public Builder register(Service... services) { -// delegate.register(services); -// return this; -// } -// -// @Override -// public Builder register(String pathPattern, Service... services) { -// delegate.register(pathPattern, services); -// return this; -// } -// -// @Override -// @SuppressWarnings("unchecked") -// public Builder register(String pathPattern, Supplier... serviceBuilders) { -// delegate.register(pathPattern, serviceBuilders); -// return this; -// } -// -// @Override -// public Builder get(Handler... requestHandlers) { -// delegate.get(requestHandlers); -// return this; -// } -// -// @Override -// public Builder get(String pathPattern, Handler... requestHandlers) { -// delegate.get(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder route(HttpRoute route) { -// delegate.register(route); -// return this; -// } -// -// @Override -// public Builder get(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.get(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder put(Handler... requestHandlers) { -// delegate.put(requestHandlers); -// return this; -// } -// -// @Override -// public Builder put(String pathPattern, Handler... requestHandlers) { -// delegate.put(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder put(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.put(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder post(Handler... requestHandlers) { -// delegate.post(requestHandlers); -// return this; -// } -// -// @Override -// public Builder post(String pathPattern, Handler... requestHandlers) { -// delegate.post(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder post(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.post(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder patch(Handler... requestHandlers) { -// delegate.patch(requestHandlers); -// return this; -// } -// -// @Override -// public Builder patch(String pathPattern, Handler... requestHandlers) { -// delegate.patch(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder patch(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.patch(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder delete(Handler... requestHandlers) { -// delegate.delete(requestHandlers); -// return this; -// } -// -// @Override -// public Builder delete(String pathPattern, Handler... requestHandlers) { -// delegate.delete(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder delete(PathMatcher pathMatcher, -// Handler... requestHandlers) { -// delegate.delete(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder options(Handler... requestHandlers) { -// delegate.options(requestHandlers); -// return this; -// } -// -// @Override -// public Builder options(String pathPattern, Handler... requestHandlers) { -// delegate.options(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder options(PathMatcher pathMatcher, -// Handler... requestHandlers) { -// delegate.options(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder head(Handler... requestHandlers) { -// delegate.head(requestHandlers); -// return this; -// } -// -// @Override -// public Builder head(String pathPattern, Handler... requestHandlers) { -// delegate.head(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder head(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.head(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder trace(Handler... requestHandlers) { -// delegate.trace(requestHandlers); -// return this; -// } -// -// @Override -// public Builder trace(String pathPattern, Handler... requestHandlers) { -// delegate.trace(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder trace(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.trace(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder any(Handler... requestHandlers) { -// delegate.any(requestHandlers); -// return this; -// } -// -// @Override -// public Builder any(String pathPattern, Handler... requestHandlers) { -// delegate.any(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder any(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.any(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder anyOf(Iterable methods, Handler... requestHandlers) { -// delegate.anyOf(methods, requestHandlers); -// return this; -// } -// -// @Override -// public Builder anyOf(Iterable methods, String pathPattern, Handler... requestHandlers) { -// delegate.anyOf(methods, pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder anyOf(Iterable methods, -// PathMatcher pathMatcher, -// Handler... requestHandlers) { -// delegate.anyOf(methods, pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder onNewWebServer(Consumer webServerConsumer) { -// delegate.onNewWebServer(webServerConsumer); -// return this; -// } -// // --------------- ERROR API -// -// /** -// * Registers an error handler that handles the given type of exceptions. -// * -// * @param exceptionClass the type of exception to handle by this handler -// * @param errorHandler the error handler -// * @param an error handler type -// * @return an updated builder -// */ -// public Builder error(Class exceptionClass, ErrorHandler errorHandler) { -// if (errorHandler == null) { -// return this; -// } -// errorHandlerRecords.add(RequestRouting.ErrorHandlerRecord.of(exceptionClass, errorHandler)); -// -// return this; -// } -// -// // --------------- BUILD API -// -// /** -// * Builds a new routing instance. -// * -// * @return a new instance -// */ -// public Routing build() { -// if (!tracingRegistered) { -// register(WebTracingConfig.create()); -// } -// RouteListRoutingRules.Aggregation aggregate = delegate.aggregate(); -// return new RequestRouting(aggregate.routeList(), errorHandlerRecords, aggregate.newWebServerCallbacks()); -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java deleted file mode 100644 index e5b1f3f4a61..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java +++ /dev/null @@ -1,763 +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.pico.builder.config.fakes.config; - -import java.time.Duration; -import java.util.Map; -import java.util.Optional; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka ServerConfiguration. - */ -@ConfigBean -public interface FakeServerConfig extends FakeSocketConfig { - - /** - * Returns the count of threads in the pool used to process HTTP requests. - *

- * Default value is {@link Runtime#availableProcessors()}. - * - * @return a workers count - */ - int workersCount(); - - /** - * Returns a server port to listen on with the default server socket. If port is - * {@code 0} then any available ephemeral port will be used. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return the server port of the default server socket - */ - @Override - int port(); - -// /** -// * Returns local address where the server listens on with the default server socket. -// * If {@code null} then listens an all local addresses. -// *

-// * Additional named server socket configuration is accessible through -// * the {@link #socket(String)} and {@link #sockets()} methods. -// * -// * @return an address to bind with the default server socket; {@code null} for all local addresses -// */ -// @Override -// InetAddress bindAddress(); - - /** - * Returns a maximum length of the queue of incoming connections on the default server - * socket. - *

- * Default value is {@link FakeSocketConfig#DEFAULT_BACKLOG_SIZE}. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return a maximum length of the queue of incoming connections - */ - @Override - int backlog(); - - /** - * Returns a default server socket timeout in milliseconds or {@code 0} for an infinite timeout. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return a default server socket timeout in milliseconds or {@code 0} - */ - @Override - int timeoutMillis(); - - /** - * Returns proposed value of the TCP receive window that is advertised to the remote peer on the - * default server socket. - *

- * If {@code 0} then use implementation default. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return a buffer size in bytes of the default server socket or {@code 0} - */ - @Override - int receiveBufferSize(); - - /** - * A socket configuration of an additional named server socket. - *

- * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured - * - * @param name the name of the additional server socket - * @return an additional named server socket configuration or {@code null} if there is no such - * named server socket - * @deprecated since 2.0.0, please use {@link #namedSocket(String)} instead - */ - @Deprecated - default FakeSocketConfig socket(String name) { - return namedSocket(name).orElse(null); - } - - /** - * A socket configuration of an additional named server socket. - *

- * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured - * - * @param name the name of the additional server socket - * @return an additional named server socket configuration or {@code empty} if there is no such - * named server socket configured - */ - default Optional namedSocket(String name) { - return Optional.ofNullable(sockets().get(name)); - } - - /** - * A map of all the configured server sockets; that is the default server socket - * which is identified by the key {@link io.helidon.pico.config.fake.helidon.WebServer#DEFAULT_SOCKET_NAME} and also all the additional - * named server socket configurations. - *

- * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured - * - * @return a map of all the configured server sockets, never null - */ - @Singular("socket") - Map sockets(); - - /** - * The maximum amount of time that the server will wait to shut - * down regardless of the value of any additionally requested - * quiet period. - * - *

The default implementation of this method returns {@link - * java.time.Duration#ofSeconds(long) Duration.ofSeconds(10L)}.

- * - * @return the {@link java.time.Duration} to use - */ -// TODO: @DefaultValue (Duration translation) - @ConfiguredOption(key = "whatever") - default Duration maxShutdownTimeout() { - return Duration.ofSeconds(10L); - } - - /** - * The quiet period during which the webserver will wait for new - * incoming connections after it has been told to shut down. - * - *

The webserver will wait no longer than the duration returned - * by the {@link #maxShutdownTimeout()} method.

- * - *

The default implementation of this method returns {@link - * java.time.Duration#ofSeconds(long) Duration.ofSeconds(0L)}, indicating - * that there will be no quiet period.

- * - * @return the {@link java.time.Duration} to use - */ - default Duration shutdownQuietPeriod() { - return Duration.ofSeconds(0L); - } - -// /** -// * Returns a Tracer. -// * -// * @return a tracer to use - never {@code null} -// */ -// Tracer tracer(); - -// /** -// * The top level {@link io.helidon.common.context.Context} to be used by this webserver. -// * @return a context instance with registered application scoped instances -// */ -// Context context(); -// -// /** -// * Returns an optional {@link Transport}. -// * -// * @return an optional {@link Transport} -// */ -// default Optional transport() { -// return Optional.ofNullable(null); -// } - - /** - * Whether to print details of HelidonFeatures. - * - * @return whether to print details - */ - boolean printFeatureDetails(); - -// /** -// * Creates new instance with defaults from external configuration source. -// * -// * @param config the externalized configuration -// * @return a new instance -// */ -// static FakeServerConfigBean create(Config config) { -// return builder(config).build(); -// } -// -// /** -// * Creates new instance of a {@link Builder server configuration builder}. -// * -// * @return a new builder instance -// * -// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()} instead -// */ -// @Deprecated -// static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Creates new instance of a {@link Builder server configuration builder} with defaults from external configuration source. -// * -// * @param config the externalized configuration -// * @return a new builder instance -// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()}, then -// * {@link WebServer.Builder#config(io.helidon.config.Config)}, or -// * {@link io.helidon.webserver.WebServer#create(Routing, io.helidon.config.Config)} -// */ -// @Deprecated -// static Builder builder(Config config) { -// return new Builder().config(config); -// } -// -// /** -// * A {@link FakeServerConfigBean} builder. -// * -// * @deprecated since 2.0.0 - use {@link io.helidon.webserver.WebServer.Builder} instead -// */ -// @Deprecated -// final class Builder implements FakeSocketConfigBean.SocketConfigurationBuilder, -// io.helidon.common.Builder { -// -// private static final AtomicInteger WEBSERVER_COUNTER = new AtomicInteger(1); -// private final Map socketBuilders = new HashMap<>(); -// private final Map socketsConfigs = new HashMap<>(); -// private int workers; -// private Tracer tracer; -// private Duration maxShutdownTimeout; -// private Duration shutdownQuietPeriod; -// private Optional transport; -// private Context context; -// private boolean printFeatureDetails; -// -// private Builder() { -// transport = Optional.ofNullable(null); -// maxShutdownTimeout = Duration.ofSeconds(10L); -// shutdownQuietPeriod = Duration.ofSeconds(0L); -// } -// -// /** -// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. -// * -// * @param sslContext ssl context -// * @return an updated builder -// */ -// public Builder ssl(SSLContext sslContext) { -// defaultSocketBuilder().ssl(sslContext); -// return this; -// } -// -// /** -// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. -// * -// * @param sslContextBuilder ssl context builder; will be built as a first step of this method execution -// * @return an updated builder -// */ -// public Builder ssl(Supplier sslContextBuilder) { -// defaultSocketBuilder().ssl(sslContextBuilder); -// return this; -// } -// -// /** -// * Sets server port. If port is {@code 0} or less then any available ephemeral port will be used. -// *

-// * Configuration key: {@code port} -// * -// * @param port the server port -// * @return an updated builder -// */ -// public Builder port(int port) { -// defaultSocketBuilder().port(port); -// return this; -// } -// -// /** -// * Sets a local address for server to bind. If {@code null} then listens an all local addresses. -// *

-// * Configuration key: {@code bind-address} -// * -// * @param bindAddress the address to bind the server or {@code null} for all local addresses -// * @return an updated builder -// */ -// public Builder bindAddress(InetAddress bindAddress) { -// defaultSocketBuilder().bindAddress(bindAddress); -// return this; -// } -// -// /** -// * Sets a maximum length of the queue of incoming connections. Default value is {@code 1024}. -// *

-// * Configuration key: {@code backlog} -// * -// * @param size the maximum length of the queue of incoming connections -// * @return an updated builder -// */ -// public Builder backlog(int size) { -// defaultSocketBuilder().backlog(size); -// return this; -// } -// -// /** -// * Sets a socket timeout in milliseconds or {@code 0} for infinite timeout. -// *

-// * Configuration key: {@code timeout} -// * -// * @param milliseconds a socket timeout in milliseconds or {@code 0} -// * @return an updated builder -// */ -// public Builder timeout(int milliseconds) { -// defaultSocketBuilder().timeoutMillis(milliseconds); -// return this; -// } -// -// /** -// * Propose value of the TCP receive window that is advertised to the remote peer. -// * If {@code 0} then implementation default is used. -// *

-// * Configuration key: {@code receive-buffer} -// * -// * @param bytes a buffer size in bytes or {@code 0} -// * @return an updated builder -// */ -// public Builder receiveBufferSize(int bytes) { -// defaultSocketBuilder().receiveBufferSize(bytes); -// return this; -// } -// -// @Override -// public Builder maxHeaderSize(int size) { -// defaultSocketBuilder().maxHeaderSize(size); -// return this; -// } -// -// @Override -// public Builder maxInitialLineLength(int length) { -// defaultSocketBuilder().maxInitialLineLength(length); -// return this; -// } -// -// /** -// * Adds an additional named server socket configuration. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param port the port to bind; if {@code 0} or less, any available ephemeral port will be used -// * @param bindAddress the address to bind; if {@code null}, all local addresses will be bound -// * @return an updated builder -// * -// * @deprecated since 2.0.0, please use {@link #addSocket(String, FakeSocketConfigBean)} instead -// */ -// @Deprecated -// public Builder addSocket(String name, int port, InetAddress bindAddress) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// return addSocket(name, FakeSocketConfigBean.builder() -// .port(port) -// .bindAddress(bindAddress)); -// } -// -// /** -// * Adds an additional named server socket configuration. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param socketConfiguration the additional named server socket configuration -// * @return an updated builder -// */ -// public Builder addSocket(String name, FakeSocketConfigBean socketConfiguration) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// this.socketsConfigs.put(name, socketConfiguration); -// return this; -// } -// -// /** -// * Adds an additional named server socket configuration. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param socketConfiguration the additional named server socket configuration builder -// * @return an updated builder -// */ -// public Builder addSocket(String name, FakeSocketConfigBean.Builder socketConfiguration) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// this.socketBuilders.put(name, socketConfiguration); -// return this; -// } -// -// /** -// * Adds an additional named server socket configuration builder. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as -// * a first step of this method execution -// * @return an updated builder -// */ -// public Builder addSocket(String name, Supplier socketConfigurationBuilder) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// -// return addSocket(name, socketConfigurationBuilder != null ? socketConfigurationBuilder.get() : null); -// } -// -// /** -// * Sets a count of threads in pool used to process HTTP requests. -// * Default value is {@code CPU_COUNT * 2}. -// *

-// * Configuration key: {@code workers} -// * -// * @param workers a workers count -// * @return an updated builder -// */ -// public Builder workersCount(int workers) { -// this.workers = workers; -// return this; -// } -// -// /** -// * Sets a tracer. -// * -// * @param tracer a tracer to set -// * @return an updated builder -// */ -// public Builder tracer(Tracer tracer) { -// this.tracer = tracer; -// return this; -// } -// -// /** -// * Sets a tracer. -// * -// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution -// * @return updated builder -// */ -// public Builder tracer(Supplier tracerBuilder) { -// return tracer(tracerBuilder.get()); -// } -// -// /** -// * Configures the SSL protocols to enable with the default server socket. -// * @param protocols protocols to enable, if {@code null} enables the -// * default protocols -// * @return an updated builder -// */ -// public Builder enabledSSlProtocols(String... protocols) { -// defaultSocketBuilder().enabledSSlProtocols(protocols); -// return this; -// } -// -// /** -// * Configures the SSL protocols to enable with the default server socket. -// * @param protocols protocols to enable, if {@code null} or empty enables -// * the default protocols -// * @return an updated builder -// */ -// public Builder enabledSSlProtocols(List protocols) { -// defaultSocketBuilder().enabledSSlProtocols(protocols); -// return this; -// } -// -// /** -// * Configure maximum client payload size. -// * @param size maximum payload size -// * @return an updated builder -// */ -// @Override -// public Builder maxPayloadSize(long size) { -// defaultSocketBuilder().maxPayloadSize(size); -// return this; -// } -// -// /** -// * Set a maximum length of the content of an upgrade request. -// *

-// * Default is {@code 64*1024} -// * -// * @param size Maximum length of the content of an upgrade request -// * @return this builder -// */ -// @Override -// public Builder maxUpgradeContentLength(int size) { -// defaultSocketBuilder().maxUpgradeContentLength(size); -// return this; -// } -// -// /** -// * Configure the maximum amount of time that the server will wait to shut -// * down regardless of the value of any additionally requested -// * quiet period. -// * @param maxShutdownTimeout the {@link Duration} to use -// * @return an updated builder -// */ -// public Builder maxShutdownTimeout(Duration maxShutdownTimeout) { -// this.maxShutdownTimeout = -// Objects.requireNonNull(maxShutdownTimeout, "Parameter 'maxShutdownTimeout' must not be null!"); -// return this; -// } -// -// /** -// * Configure the quiet period during which the webserver will wait for new -// * incoming connections after it has been told to shut down. -// * @param shutdownQuietPeriod the {@link Duration} to use -// * @return an updated builder -// */ -// public Builder shutdownQuietPeriod(Duration shutdownQuietPeriod) { -// this.shutdownQuietPeriod = -// Objects.requireNonNull(shutdownQuietPeriod, "Parameter 'shutdownQuietPeriod' must not be null!"); -// return this; -// } -// -// /** -// * Configure transport. -// * @param transport a {@link Transport} -// * @return an updated builder -// */ -// public Builder transport(Transport transport) { -// this.transport = Optional.of(transport); -// return this; -// } -// -// /** -// * Set to {@code true} to print detailed feature information on startup. -// * -// * @param print whether to print details or not -// * @return updated builder instance -// * @see io.helidon.common.HelidonFeatures -// */ -// public Builder printFeatureDetails(boolean print) { -// this.printFeatureDetails = print; -// return this; -// } -// -// /** -// * Configure the application scoped context to be used as a parent for webserver request contexts. -// * @param context top level context -// * @return an updated builder -// */ -// public Builder context(Context context) { -// this.context = context; -// -// return this; -// } -// -// private InetAddress string2InetAddress(String address) { -// try { -// return InetAddress.getByName(address); -// } catch (UnknownHostException e) { -// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); -// } -// } -// -// /** -// * Sets configuration values included in provided {@link Config} parameter. -// *

-// * It can be used for configuration externalisation. -// *

-// * All parameters sets before this method call can be seen as defaults and all parameters sets after can be seen -// * as forced. -// * -// * @param config the configuration to use -// * @return an updated builder -// */ -// public Builder config(Config config) { -// if (config == null) { -// return this; -// } -// -// defaultSocketBuilder().config(config); -// -// config.get("host").asString().ifPresent(defaultSocketBuilder()::host); -// -// DeprecatedConfig.get(config, "worker-count", "workers") -// .asInt() -// .ifPresent(this::workersCount); -// -// config.get("features.print-details").asBoolean().ifPresent(this::printFeatureDetails); -// -// // shutdown timeouts -// config.get("max-shutdown-timeout-seconds").asLong().ifPresent(it -> maxShutdownTimeout(Duration.ofSeconds(it))); -// config.get("shutdown-quiet-period-seconds").asLong().ifPresent(it -> shutdownQuietPeriod(Duration.ofSeconds(it))); -// -// // sockets -// Config socketsConfig = config.get("sockets"); -// if (socketsConfig.exists()) { -// List socketConfigs = socketsConfig.asNodeList().orElse(List.of()); -// for (Config socketConfig : socketConfigs) { -// // the whole section checking the socket name can be removed -// // when we remove deprecated methods with socket name on server builder -// String socketName; -// -// String nodeName = socketConfig.name(); -// Optional maybeSocketName = socketConfig.get("name").asString().asOptional(); -// -// socketName = maybeSocketName.orElse(nodeName); -// -// // log warning for deprecated config -// try { -// Integer.parseInt(nodeName); -// if (socketName.equals(nodeName) && maybeSocketName.isEmpty()) { -// throw new ConfigException("Cannot find \"name\" key for socket configuration " + socketConfig.key()); -// } -// } catch (NumberFormatException e) { -// // this is old approach -// Logger.getLogger(SocketConfigurationBuilder.class.getName()) -// .warning("Socket configuration at " + socketConfig.key() + " is deprecated. Please use an array " -// + "with \"name\" key to define the socket name."); -// } -// -// FakeSocketConfigBean.Builder socket = FakeSocketConfigBean.builder() -// .name(socketName) -// .config(socketConfig); -// -// socketBuilders.put(socket.name(), socket); -// } -// } -// -// return this; -// } -// -// /** -// * Builds a new configuration instance. -// * -// * @return a new instance -// */ -// @Override -// public FakeServerConfigBean build() { -// if (null == context) { -// // I do not expect "unlimited" number of webservers -// // in case somebody spins a huge number up, the counter will cycle to negative numbers once -// // Integer.MAX_VALUE is reached. -// context = Context.builder() -// .id("web-" + WEBSERVER_COUNTER.getAndIncrement()) -// .build(); -// } -// -// Optional maybeTracer = context.get(Tracer.class); -// -// if (null == this.tracer) { -// this.tracer = maybeTracer.orElseGet(Tracer::global); -// } -// -// if (maybeTracer.isEmpty()) { -// context.register(this.tracer); -// } -// -// if (workers <= 0) { -// workers = Runtime.getRuntime().availableProcessors(); -// } -// -// return new ServerBasicConfig(this); -// } -// -// FakeSocketConfigBean.Builder defaultSocketBuilder() { -// return socketBuilder(WebServer.DEFAULT_SOCKET_NAME); -// } -// -// FakeSocketConfigBean.Builder socketBuilder(String socketName) { -// return socketBuilders.computeIfAbsent(socketName, k -> FakeSocketConfigBean.builder().name(socketName)); -// } -// -// Map sockets() { -// Set builtSocketConfigsKeys = socketsConfigs.keySet(); -// Map result = -// new HashMap<>(this.socketBuilders.size() + this.socketsConfigs.size()); -// for (Map.Entry e : this.socketBuilders.entrySet()) { -// String key = e.getKey(); -// if (builtSocketConfigsKeys.contains(key)) { -// throw new IllegalStateException("Both mutable and immutable socket configuration provided for named socket " -// + key); -// } -// result.put(key, e.getValue().build()); -// } -// -// result.putAll(this.socketsConfigs); -// return result; -// } -// -// int workers() { -// return workers; -// } -// -// Tracer tracer() { -// return tracer; -// } -// -// Duration maxShutdownTimeout() { -// return maxShutdownTimeout; -// } -// -// Duration shutdownQuietPeriod() { -// return shutdownQuietPeriod; -// } -// -// Optional transport() { -// return transport; -// } -// -// Context context() { -// return context; -// } -// -// boolean printFeatureDetails() { -// return printFeatureDetails; -// } -// -// @Override -// public Builder timeout(long amount, TimeUnit unit) { -// defaultSocketBuilder().timeout(amount, unit); -// return this; -// } -// -// @Override -// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { -// defaultSocketBuilder().tls(webServerTls); -// return this; -// } -// -// @Override -// public Builder enableCompression(boolean value) { -// defaultSocketBuilder().enableCompression(value); -// return this; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java deleted file mode 100644 index 49dd3296f63..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java +++ /dev/null @@ -1,38 +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.pico.builder.config.fakes.config; - -/** - * aka ServerLifecycle. - * - * Basic server lifecycle operations. - */ -public interface FakeServerLifecycle { - -// /** -// * Before server start. -// */ -// default void beforeStart() { -// } -// -// /** -// * After server stop. -// */ -// default void afterStop() { -// } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java deleted file mode 100644 index 6adf615a31b..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java +++ /dev/null @@ -1,849 +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.pico.builder.config.fakes.config; - -/* - * 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 java.util.Optional; -import java.util.Set; - -import javax.net.ssl.SSLContext; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.config.ConfigBean; -import io.helidon.pico.builder.config.fakes.WebServer; - -/** - * aka ServerConfiguration. - * - * The SocketConfiguration configures a port to listen on and its associated server socket parameters. - */ -@ConfigBean -public interface FakeSocketConfig { - - /** - * The default backlog size to configure the server sockets with if no other value - * is provided. - */ - int DEFAULT_BACKLOG_SIZE = 1024; - - /** - * Name of this socket. - * Default to WebServer#DEFAULT_SOCKET_NAME for the main and - * default server socket. All other sockets must be named. - * - * @return name of this socket - */ -// default String name() { -// return WebServer.DEFAULT_SOCKET_NAME; -// } - @ConfiguredOption(WebServer.DEFAULT_SOCKET_NAME) - String name(); - - /** - * Returns a server port to listen on with the server socket. If port is - * {@code 0} then any available ephemeral port will be used. - * - * @return the server port of the server socket - */ - int port(); - -// /** -// * Returns local address where the server listens on with the server socket. -// * If {@code null} then listens an all local addresses. -// * -// * @return an address to bind with the server socket; {@code null} for all local addresses -// */ -// InetAddress bindAddress(); - @ConfiguredOption(key = "bind-address") - String bindAddress(); - - /** - * Returns a maximum length of the queue of incoming connections on the server - * socket. - *

- * Default value is {@link #DEFAULT_BACKLOG_SIZE}. - * - * @return a maximum length of the queue of incoming connections - */ - @ConfiguredOption("1024") - int backlog(); - - /** - * Returns a server socket timeout in milliseconds or {@code 0} for an infinite timeout. - * - * @return a server socket timeout in milliseconds or {@code 0} - */ - @ConfiguredOption(key = "timeout-millis") - int timeoutMillis(); - - /** - * Returns proposed value of the TCP receive window that is advertised to the remote peer on the - * server socket. - *

- * If {@code 0} then use implementation default. - * - * @return a buffer size in bytes of the server socket or {@code 0} - */ - int receiveBufferSize(); - - /** - * Return a {@link FakeWebServerTlsConfig} containing server TLS configuration. When empty {@link java.util.Optional} is returned - * no TLS should be configured. - * - * @return web server tls configuration - */ - Optional tls(); - - /** - * Returns a {@link javax.net.ssl.SSLContext} to use with the server socket. If not {@code null} then - * the server enforces an SSL communication. - * - * @deprecated use {@code tls().sslContext()} instead. This method will be removed at 3.0.0 version. - * @return a SSL context to use - */ - @Deprecated(since = "2.3.1", forRemoval = true) - SSLContext ssl(); - - /** - * Returns the SSL protocols to enable, or {@code null} to enable the default - * protocols. - * @deprecated use {@code tls().enabledTlsProtocols()} instead. This method will be removed at 3.0.0 version. - * @return the SSL protocols to enable - */ - @Deprecated(since = "2.3.1", forRemoval = true) - Set enabledSslProtocols(); - - /** - * Return the allowed cipher suite of the TLS. If empty set is returned, the default cipher suite is used. - * - * @deprecated use {@code tls().cipherSuite()} instead. This method will be removed at 3.0.0 version. - * @return the allowed cipher suite - */ - @Deprecated(since = "2.3.1", forRemoval = true) - Set allowedCipherSuite(); - - /** - * Whether to require client authentication or not. - * - * @deprecated use {@code tls().clientAuth()} instead. This method will be removed at 3.0.0 version. - * @return client authentication - */ - @Deprecated(since = "2.3.1", forRemoval = true) - FakeNettyClientAuth clientAuth(); - - /** - * Whether this socket is enabled (and will be opened on server startup), or disabled - * (and ignored on server startup). - * - * @return {@code true} for enabled socket, {@code false} for socket that should not be opened - */ -// default boolean enabled() { -// return true; -// } - @ConfiguredOption("true") - boolean enabled(); - - /** - * Maximal size of all headers combined. - * - * @return size in bytes - */ - // TODO: should we automatically translate camel-case to dashes? - @ConfiguredOption(key = "max-header-size", value = "8192") - int maxHeaderSize(); - - /** - * Maximal length of the initial HTTP line. - * - * @return length - */ - @ConfiguredOption("4096") - int maxInitialLineLength(); - - /** - * Maximal size of a single chunk of received data. - * - * @return chunk size - */ - int maxChunkSize(); - - /** - * Whether to validate HTTP header names. - * When set to {@code true}, we make sure the header name is a valid string - * - * @return {@code true} if headers should be validated - */ - boolean validateHeaders(); - - /** - * Whether to allow negotiation for a gzip/deflate content encoding. Supporting - * HTTP compression may interfere with application that use streaming and other - * similar features. Thus, it defaults to {@code false}. - * - * @return compression flag - */ -// default boolean enableCompression() { -// return false; -// } - boolean enableCompression(); - - /** - * Maximum size allowed for an HTTP payload in a client request. A negative - * value indicates that there is no maximum set. - * - * @return maximum payload size - */ -// default long maxPayloadSize() { -// return -1L; -// } - @ConfiguredOption("-1") - long maxPayloadSize(); - - /** - * Initial size of the buffer used to parse HTTP line and headers. - * - * @return initial size of the buffer - */ - int initialBufferSize(); - - /** - * Maximum length of the content of an upgrade request. - * - * @return maximum length of the content of an upgrade request - */ -// default int maxUpgradeContentLength() { -// return 64 * 1024; -// } - @ConfiguredOption("65536") - int maxUpgradeContentLength(); - -// /** -// * Creates a builder of {@link FakeSocketConfigBean} class. -// * -// * @return a builder -// */ -// static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Create a default named configuration. -// * -// * @param name name of the socket -// * @return a new socket configuration with defaults -// */ -// static FakeSocketConfigBean create(String name) { -// return builder() -// .name(name) -// .build(); -// } -// -// /** -// * Socket configuration builder API, used by {@link io.helidon.webserver.SocketConfiguration.Builder} -// * to configure additional sockets, and by {@link io.helidon.webserver.WebServer.Builder} to -// * configure the default socket. -// * -// * @param type of the subclass of this class to provide correct fluent API -// */ -// @Configured -// interface SocketConfigurationBuilder> { -// /** -// * Configures a server port to listen on with the server socket. If port is -// * {@code 0} then any available ephemeral port will be used. -// * -// * @param port the server port of the server socket -// * @return this builder -// */ -// @ConfiguredOption("0") -// B port(int port); -// -// /** -// * Configures local address where the server listens on with the server socket. -// * If not configured, then listens an all local addresses. -// * -// * @param address an address to bind with the server socket -// * @return this builder -// * @throws java.lang.NullPointerException in case the bind address is null -// * @throws io.helidon.config.ConfigException in case the address provided is not a valid host address -// */ -// @ConfiguredOption(deprecated = true) -// default B bindAddress(String address) { -// try { -// return bindAddress(InetAddress.getByName(address)); -// } catch (UnknownHostException e) { -// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); -// } -// } -// -// /** -// * A helper method that just calls {@link #bindAddress(String)}. -// * -// * @param address host to listen on -// * @return this builder -// */ -// @ConfiguredOption -// default B host(String address) { -// return bindAddress(address); -// } -// -// /** -// * Configures local address where the server listens on with the server socket. -// * If not configured, then listens an all local addresses. -// * -// * @param bindAddress an address to bind with the server socket -// * @return this builder -// * @throws java.lang.NullPointerException in case the bind address is null -// */ -// B bindAddress(InetAddress bindAddress); -// -// /** -// * Configures a maximum length of the queue of incoming connections on the server -// * socket. -// *

-// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. -// * -// * @param backlog a maximum length of the queue of incoming connections -// * @return this builder -// */ -// @ConfiguredOption("1024") -// B backlog(int backlog); -// -// /** -// * Configures a server socket timeout. -// * -// * @param amount an amount of time to configure the timeout, use {@code 0} for infinite timeout -// * @param unit time unit to use with the configured amount -// * @return this builder -// */ -// @ConfiguredOption(key = "timeout-millis", type = Long.class, value = "0", -// description = "Socket timeout in milliseconds") -// B timeout(long amount, TimeUnit unit); -// -// /** -// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the -// * server socket. -// *

-// * If {@code 0} then use implementation default. -// * -// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} -// * @return this builder -// */ -// @ConfiguredOption -// B receiveBufferSize(int receiveBufferSize); -// -// /** -// * Configures SSL for this socket. When configured, the server enforces SSL -// * configuration. -// * If this method is called, any other method except for {@link #tls(java.util.function.Supplier)}¨ -// * and repeated invocation of this method would be ignored. -// *

-// * If this method is called again, the previous configuration would be ignored. -// * -// * @param webServerTls ssl configuration to use with this socket -// * @return this builder -// */ -// @ConfiguredOption -// B tls(FakeWebServerTlsConfigBean webServerTls); -// -// /** -// * Configures SSL for this socket. When configured, the server enforces SSL -// * configuration. -// * -// * @param tlsConfig supplier ssl configuration to use with this socket -// * @return this builder -// */ -// default B tls(Supplier tlsConfig) { -// return tls(tlsConfig.get()); -// } -// -// /** -// * Maximal number of bytes of all header values combined. When a bigger value is received, a -// * {@link io.helidon.common.http.Http.Status#BAD_REQUEST_400} -// * is returned. -// *

-// * Default is {@code 8192} -// * -// * @param size maximal number of bytes of combined header values -// * @return this builder -// */ -// @ConfiguredOption("8192") -// B maxHeaderSize(int size); -// -// /** -// * Maximal number of characters in the initial HTTP line. -// *

-// * Default is {@code 4096} -// * -// * @param length maximal number of characters -// * @return this builder -// */ -// @ConfiguredOption("4096") -// B maxInitialLineLength(int length); -// -// /** -// * Enable negotiation for gzip/deflate content encodings. Clients can -// * request compression using the "Accept-Encoding" header. -// *

-// * Default is {@code false} -// * -// * @param value compression flag -// * @return this builder -// */ -// @ConfiguredOption("false") -// B enableCompression(boolean value); -// -// /** -// * Set a maximum payload size for a client request. Can prevent DoS -// * attacks. -// * -// * @param size maximum payload size -// * @return this builder -// */ -// @ConfiguredOption -// B maxPayloadSize(long size); -// -// /** -// * Set a maximum length of the content of an upgrade request. -// *

-// * Default is {@code 64*1024} -// * -// * @param size Maximum length of the content of an upgrade request -// * @return this builder -// */ -// @ConfiguredOption("65536") -// B maxUpgradeContentLength(int size); -// -// /** -// * Update this socket configuration from a {@link io.helidon.config.Config}. -// * -// * @param config configuration on the node of a socket -// * @return updated builder instance -// */ -// @SuppressWarnings("unchecked") -// default B config(Config config) { -// config.get("port").asInt().ifPresent(this::port); -// config.get("bind-address").asString().ifPresent(this::host); -// config.get("backlog").asInt().ifPresent(this::backlog); -// config.get("max-header-size").asInt().ifPresent(this::maxHeaderSize); -// config.get("max-initial-line-length").asInt().ifPresent(this::maxInitialLineLength); -// config.get("max-payload-size").asInt().ifPresent(this::maxPayloadSize); -// -// DeprecatedConfig.get(config, "timeout-millis", "timeout") -// .asInt() -// .ifPresent(it -> this.timeout(it, TimeUnit.MILLISECONDS)); -// DeprecatedConfig.get(config, "receive-buffer-size", "receive-buffer") -// .asInt() -// .ifPresent(this::receiveBufferSize); -// -// Optional> enabledProtocols = DeprecatedConfig.get(config, "ssl.protocols", "ssl-protocols") -// .asList(String.class) -// .asOptional(); -// -// // tls -// Config sslConfig = DeprecatedConfig.get(config, "tls", "ssl"); -// if (sslConfig.exists()) { -// try { -// FakeWebServerTlsConfigBean.Builder builder = FakeWebServerTlsConfigBean.builder(); -// enabledProtocols.ifPresent(builder::enabledProtocols); -// builder.config(sslConfig); -// -// this.tls(builder.build()); -// } catch (IllegalStateException e) { -// throw new ConfigException("Cannot load SSL configuration.", e); -// } -// } -// -// // compression -// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); -// return (B) this; -// } -// } -// -// /** -// * The {@link io.helidon.webserver.SocketConfiguration} builder class. -// */ -// @Configured -// final class Builder implements SocketConfigurationBuilder, io.helidon.common.Builder { -// /** -// * @deprecated remove once WebServer.Builder.addSocket(name, socket) methods are removed -// */ -// @Deprecated -// static final String UNCONFIGURED_NAME = "io.helidon.webserver.SocketConfiguration.UNCONFIGURED"; -// private final FakeWebServerTlsConfigBean.Builder tlsConfigBuilder = FakeWebServerTlsConfigBean.builder(); -// -// private int port = 0; -// private InetAddress bindAddress = null; -// private int backlog = DEFAULT_BACKLOG_SIZE; -// private int timeoutMillis = 0; -// private int receiveBufferSize = 0; -// private FakeWebServerTlsConfigBean webServerTls; -// // this is for backward compatibility, should be initialized to null once the -// // methods with `name` are removed from server builder (for adding sockets) -// private String name = UNCONFIGURED_NAME; -// private boolean enabled = true; -// // these values are as defined in Netty implementation -// private int maxHeaderSize = 8192; -// private int maxInitialLineLength = 4096; -// private int maxChunkSize = 8192; -// private boolean validateHeaders = true; -// private int initialBufferSize = 128; -// private boolean enableCompression = false; -// private long maxPayloadSize = -1; -// private int maxUpgradeContentLength = 64 * 1024; -// -// private Builder() { -// } -// -// @Override -// public FakeSocketConfigBean build() { -// if (null == webServerTls) { -// webServerTls = tlsConfigBuilder.build(); -// } -// -// if (null == name) { -// throw new ConfigException("Socket name must be configured for each socket"); -// } -// -// return new ServerBasicConfig.SocketConfig(this); -// } -// -// @Override -// public Builder port(int port) { -// this.port = port; -// return this; -// } -// -// @Override -// public Builder bindAddress(InetAddress bindAddress) { -// this.bindAddress = bindAddress; -// return this; -// } -// -// /** -// * Configures a maximum length of the queue of incoming connections on the server -// * socket. -// *

-// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. -// * -// * @param backlog a maximum length of the queue of incoming connections -// * @return this builder -// */ -// public Builder backlog(int backlog) { -// this.backlog = backlog; -// return this; -// } -// -// /** -// * Configures a server socket timeout in milliseconds or {@code 0} for an infinite timeout. -// * -// * @param timeoutMillis a server socket timeout in milliseconds or {@code 0} -// * @return this builder -// * -// * @deprecated since 2.0.0 please use {@link #timeout(long, java.util.concurrent.TimeUnit)} instead -// */ -// @Deprecated -// public Builder timeoutMillis(int timeoutMillis) { -// this.timeoutMillis = timeoutMillis; -// return this; -// } -// -// /** -// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the -// * server socket. -// *

-// * If {@code 0} then use implementation default. -// * -// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} -// * @return this builder -// */ -// @Override -// public Builder receiveBufferSize(int receiveBufferSize) { -// this.receiveBufferSize = receiveBufferSize; -// return this; -// } -// -// /** -// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then -// * the server enforces an SSL communication. -// * -// * @param sslContext a SSL context to use -// * @return this builder -// * -// * @deprecated since 2.0.0, please use {@link #tls(FakeWebServerTlsConfigBean)} instead -// */ -// @Deprecated -// public Builder ssl(SSLContext sslContext) { -// if (null != sslContext) { -// this.tlsConfigBuilder.sslContext(sslContext); -// } -// return this; -// } -// -// /** -// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then -// * the server enforces an SSL communication. -// * -// * @param sslContextBuilder a SSL context builder to use; will be built as a first step of this -// * method execution -// * @return this builder -// * @deprecated since 2.0.0, please use {@link #tls(Supplier)} instead -// */ -// @Deprecated -// public Builder ssl(Supplier sslContextBuilder) { -// return ssl(sslContextBuilder != null ? sslContextBuilder.get() : null); -// } -// -// /** -// * Configures the SSL protocols to enable with the server socket. -// * @param protocols protocols to enable, if {@code null} enables the -// * default protocols -// * @return this builder -// * -// * @deprecated since 2.0.0, please use {@link FakeWebServerTlsConfigBean.Builder#enabledProtocols(String...)} -// * instead -// */ -// @Deprecated -// public Builder enabledSSlProtocols(String... protocols) { -// if (null == protocols) { -// enabledSSlProtocols(List.of()); -// } else { -// enabledSSlProtocols(Arrays.asList(protocols)); -// } -// return this; -// } -// -// /** -// * Configures the SSL protocols to enable with the server socket. -// * @param protocols protocols to enable, if {@code null} or empty enables -// * the default protocols -// * @return this builder -// */ -// @Deprecated -// public Builder enabledSSlProtocols(List protocols) { -// if (null == protocols) { -// this.tlsConfigBuilder.enabledProtocols(List.of()); -// } else { -// this.tlsConfigBuilder.enabledProtocols(protocols); -// } -// return this; -// } -// -// @Override -// public Builder timeout(long amount, TimeUnit unit) { -// long timeout = unit.toMillis(amount); -// if (timeout > Integer.MAX_VALUE) { -// this.timeoutMillis = 0; -// } else { -// this.timeoutMillis = (int) timeout; -// } -// return this; -// } -// -// @Override -// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { -// this.webServerTls = webServerTls; -// return this; -// } -// -// @Override -// public Builder maxHeaderSize(int size) { -// this.maxHeaderSize = size; -// return this; -// } -// -// @Override -// public Builder maxInitialLineLength(int length) { -// this.maxInitialLineLength = length; -// return this; -// } -// -// @Override -// public Builder maxPayloadSize(long size) { -// this.maxPayloadSize = size; -// return this; -// } -// -// @Override -// public Builder maxUpgradeContentLength(int size) { -// this.maxUpgradeContentLength = size; -// return this; -// } -// -// /** -// * Configure a socket name, to bind named routings to. -// * -// * @param name name of the socket -// * @return updated builder instance -// */ -// @ConfiguredOption(required = true) -// public Builder name(String name) { -// this.name = name; -// return this; -// } -// -// /** -// * Set this socket builder to enabled or disabled. -// * -// * @param enabled when set to {@code false}, the socket is not going to be opened by the server -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = enabled; -// return this; -// } -// -// /** -// * Configure maximal size of a chunk to be read from incoming requests. -// * Defaults to {@code 8192}. -// * -// * @param size maximal chunk size -// * @return updated builder instance -// */ -// public Builder maxChunkSize(int size) { -// this.maxChunkSize = size; -// return this; -// } -// -// /** -// * Configure whether to validate header names. -// * Defaults to {@code true} to make sure header names are valid strings. -// * -// * @param validate set to {@code false} to ignore header validation -// * @return updated builder instance -// */ -// public Builder validateHeaders(boolean validate) { -// this.validateHeaders = validate; -// return this; -// } -// -// /** -// * Configure initial size of the buffer used to parse HTTP line and headers. -// * Defaults to {@code 128}. -// * -// * @param size initial buffer size -// * @return updated builder instance -// */ -// public Builder initialBufferSize(int size) { -// this.initialBufferSize = size; -// return this; -// } -// -// /** -// * Configure whether to enable content negotiation for compression. -// * -// * @param value compression flag -// * @return updated builder instance -// */ -// public Builder enableCompression(boolean value) { -// this.enableCompression = value; -// return this; -// } -// -// @Override -// public Builder config(Config config) { -// SocketConfigurationBuilder.super.config(config); -// -// config.get("name").asString().ifPresent(this::name); -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// config.get("max-chunk-size").asInt().ifPresent(this::maxChunkSize); -// config.get("validate-headers").asBoolean().ifPresent(this::validateHeaders); -// config.get("initial-buffer-size").asInt().ifPresent(this::initialBufferSize); -// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); -// -// return this; -// } -// -// int port() { -// return port; -// } -// -// Optional bindAddress() { -// return Optional.ofNullable(bindAddress); -// } -// -// int backlog() { -// return backlog; -// } -// -// int timeoutMillis() { -// return timeoutMillis; -// } -// -// int receiveBufferSize() { -// return receiveBufferSize; -// } -// -// FakeWebServerTlsConfigBean tlsConfig() { -// return webServerTls; -// } -// -// String name() { -// return name; -// } -// -// boolean enabled() { -// return enabled; -// } -// -// int maxHeaderSize() { -// return maxHeaderSize; -// } -// -// int maxInitialLineLength() { -// return maxInitialLineLength; -// } -// -// int maxChunkSize() { -// return maxChunkSize; -// } -// -// boolean validateHeaders() { -// return validateHeaders; -// } -// -// int initialBufferSize() { -// return initialBufferSize; -// } -// -// boolean enableCompression() { -// return enableCompression; -// } -// -// long maxPayloadSize() { -// return maxPayloadSize; -// } -// -// int maxUpgradeContentLength() { -// return maxUpgradeContentLength; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java deleted file mode 100644 index 719ffc6b3e9..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java +++ /dev/null @@ -1,128 +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.pico.builder.config.fakes.config; - -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka SpanLogTracingConfig. - */ -@ConfigBean -public interface FakeSpanLogTracingConfig extends FakeTraceableConfig { -// /** -// * Disabled traced span log. -// */ -// public static final FakeSpanLogTracingConfigBean DISABLED = FakeSpanLogTracingConfigBean.builder("disabled").enabled(false).build(); -// /** -// * Enabled traced span log. -// */ -// public static final FakeSpanLogTracingConfigBean ENABLED = FakeSpanLogTracingConfigBean.builder("enabled").build(); -// -// /** -// * A new span log. -// * @param name name of the span log -// */ -// protected FakeSpanLogTracingConfigBean(String name) { -// super(name); -// } -// - -// /** -// * Merge two traced span log configurations. -// * -// * @param older original configuration with default values -// * @param newer new configuration to override the older -// * @return a new traced span log mergint the older and newer -// */ -// static FakeSpanLogTracingConfigBean merge(FakeSpanLogTracingConfigBean older, FakeSpanLogTracingConfigBean newer) { -// return new FakeSpanLogTracingConfigBean(newer.name()) { -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// }; -// } -// -// /** -// * Fluent API builder to create a new traced span log configuration. -// * -// * @param name name of the span log -// * @return a new builder instance -// */ -// public static Builder builder(String name) { -// return new Builder(name); -// } -// -// /** -// * Create a new traced span log configuration from {@link io.helidon.config.Config}. -// * -// * @param name name of the span log -// * @param config config for a traced span log -// * @return a new traced span log configuration -// */ -// public static FakeSpanLogTracingConfigBean create(String name, Config config) { -// return builder(name).config(config).build(); -// } -// -// /** -// * A fluent API builder for {@link FakeSpanLogTracingConfigBean}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final String name; -// private Optional enabled = Optional.empty(); -// -// private Builder(String name) { -// this.name = name; -// } -// -// @Override -// public FakeSpanLogTracingConfigBean build() { -// final Optional finalEnabled = enabled; -// return new FakeSpanLogTracingConfigBean(name) { -// @Override -// public Optional isEnabled() { -// return finalEnabled; -// } -// }; -// } -// -// /** -// * Configure whether this traced span log is enabled or disabled. -// * -// * @param enabled if disabled, this span and all logs will be disabled -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// -// /** -// * Update this builder from {@link io.helidon.config.Config}. -// * -// * @param config config of a traced span log -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// -// return this; -// } -// } -// -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java deleted file mode 100644 index 39a3e2a8130..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java +++ /dev/null @@ -1,258 +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.pico.builder.config.fakes.config; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka SpanTracingConfig. - * - * Configuration of a single traced span. - */ -@ConfigBean -public interface FakeSpanTracingConfig extends FakeTraceableConfig { - -// /** -// * A traced span that is disabled and all logs on it are disabled as well. -// */ -// public static final SpanTracingConfig DISABLED = SpanTracingConfig.builder("disabled").enabled(false).build(); -// /** -// * A traced span that is inabled and all logs on it are enabled as well. -// */ -// public static final SpanTracingConfig ENABLED = SpanTracingConfig.builder("enabled").build(); - -// /** -// * A new traceable span. -// * -// * @param name name of this span -// */ -// protected SpanTracingConfig(String name) { -// super(name); -// } -// -// @Override -// public String toString() { -// return "SpanTracingConfig(" + name() + ")"; -// } -// -// /** -// * Merge configuration of two traced spans. -// * -// * @param older older span with default values -// * @param newer newer span overriding values in older -// * @return a new merged traced span configuration -// */ -// static SpanTracingConfig merge(SpanTracingConfig older, SpanTracingConfig newer) { -// return new SpanTracingConfig(newer.name()) { -// @Override -// public Optional newName() { -// return newer.newName() -// .or(older::newName); -// } -// -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// -// @Override -// public Optional getSpanLog(String name) { -// Optional newLog = newer.getSpanLog(name); -// Optional oldLog = older.getSpanLog(name); -// -// if (newLog.isPresent() && oldLog.isPresent()) { -// return Optional.of(SpanLogTracingConfig.merge(oldLog.get(), newLog.get())); -// } -// -// if (newLog.isPresent()) { -// return newLog; -// } -// -// return oldLog; -// } -// }; -// } - - /** - * When rename is desired, returns the new name. - * - * @return new name for this span or empty when rename is not desired - */ - Optional newName(); - -// /** -// * Configuration of a traced span log. -// * -// * @param name name of the log event -// * @return configuration of the log event, or empty if not explicitly configured (used when merging) -// */ -// protected abstract Optional getSpanLog(String name); - - @Singular("spanLog") // B addSpanLog(String, FakeSpanLogTracingConfigBean); - Map spanLogMap(); - -// /** -// * Configuration of a traceable span log. -// * If this span is disabled, the log is always disabled. -// * -// * @param name name of the log event -// * @return configuration of the log event -// */ -// public final SpanLogTracingConfig spanLog(String name) { -// if (enabled()) { -// return getSpanLog(name).orElse(SpanLogTracingConfig.ENABLED); -// } else { -// return SpanLogTracingConfig.DISABLED; -// } -// } -// -// /** -// * Whether a log event should be logged on the span with a default value. -// * -// * @param logName name of the log event -// * @param defaultValue to use in case the log event is not configured in this span's configuration -// * @return whether to log ({@code true}) the event or not ({@code false}), uses the default value for unconfigured logs -// */ -// public boolean logEnabled(String logName, boolean defaultValue) { -// if (enabled()) { -// return getSpanLog(logName).map(Traceable::enabled).orElse(defaultValue); -// } -// return false; -// } -// -// /** -// * A fluent API builder to create traced span configuration. -// * -// * @param name name of the span -// * @return a new builder instance -// */ -// public static Builder builder(String name) { -// return new Builder(name); -// } -// -// /** -// * Create traced span configuration from a {@link io.helidon.config.Config}. -// * -// * @param name name of the span -// * @param config config to load span configuration from -// * @return a new traced span configuration -// */ -// public static SpanTracingConfig create(String name, Config config) { -// return builder(name).config(config).build(); -// } -// -// /** -// * A fluent API builder for {@link SpanTracingConfig}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final Map spanLogMap = new HashMap<>(); -// private final String name; -// private Optional enabled = Optional.empty(); -// private String newName; -// -// private Builder(String name) { -// this.name = name; -// } -// -// @Override -// public SpanTracingConfig build() { -// final Map finalSpanLogMap = new HashMap<>(spanLogMap); -// final Optional finalNewName = Optional.ofNullable(newName); -// final Optional finalEnabled = enabled; -// -// return new SpanTracingConfig(name) { -// @Override -// public Optional newName() { -// return finalNewName; -// } -// -// @Override -// public Optional isEnabled() { -// return finalEnabled; -// } -// -// @Override -// protected Optional getSpanLog(String name) { -// if (enabled.orElse(true)) { -// return Optional.ofNullable(finalSpanLogMap.get(name)); -// } -// return Optional.of(SpanLogTracingConfig.DISABLED); -// } -// }; -// } -// -// /** -// * Configure whether this traced span is enabled or disabled. -// * -// * @param enabled if disabled, this span and all logs will be disabled -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// -// /** -// * Configure a new name of this span. -// * -// * @param newName new name to use when reporting this span -// * @return updated builder instance -// */ -// public Builder newName(String newName) { -// this.newName = newName; -// return this; -// } -// -// /** -// * Add configuration of a traced span log. -// * -// * @param spanLogTracingConfig configuration of the traced span log -// * @return updated builder instance -// */ -// public Builder addSpanLog(SpanLogTracingConfig spanLogTracingConfig) { -// this.spanLogMap.put(spanLogTracingConfig.name(), spanLogTracingConfig); -// return this; -// } -// -// /** -// * Update this builder from {@link io.helidon.config.Config}. -// * -// * @param config configuration of this span -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// config.get("new-name").asString().ifPresent(this::newName); -// config.get("logs") -// .asNodeList() -// .ifPresent(nodes -> { -// nodes.forEach(node -> { -// // name is mandatory -// addSpanLog(SpanLogTracingConfig.create(node.get("name").asString().get(), node)); -// }); -// }); -// -// return this; -// } -// } -// -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java deleted file mode 100644 index ff675ee14f8..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java +++ /dev/null @@ -1,56 +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.pico.builder.config.fakes.config; - -import java.util.Optional; - -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka Traceable. - * - * Tracing configuration that can be enabled or disabled. - */ -@ConfigBean -public interface FakeTraceableConfig { - /** - * Whether this trace should be executed or not. - * - * @return {@code true} if span/component should be traced, - * {@code false} if it should not, - * {@code empty} when this flag is not explicitly configured - */ - /*protected*/ Optional isEnabled(); - - /** - * Name of this traceable unit. - * - * @return name - */ - String name(); - - /** - * Whether this traceable should be executed or not. - * - * @return {@code true} if span/component should be traced, - * {@code false} if it should not - */ - default boolean enabled() { - return isEnabled().orElse(true); - } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java deleted file mode 100644 index 2e6c258f71b..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java +++ /dev/null @@ -1,103 +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.pico.builder.config.fakes.config; - -/** - * Tracer abstraction. - * Tracer is the central point that collects tracing spans, and (probably) pushes them to backend. - */ -public interface FakeTracer { -// /** -// * Create a no-op tracer. All spans created from this tracer are not doing anything. -// * -// * @return no-op tracer -// */ -// static Tracer noOp() { -// return NoOpTracer.instance(); -// } -// -// /** -// * Get the currently registered global tracer. -// * -// * @return global tracer -// */ -// static Tracer global() { -// return TracerProviderHelper.global(); -// } -// -// /** -// * Register a global tracer, behavior depends on implementation. -// * -// * @param tracer tracer to use as a global tracer -// */ -// -// static void global(Tracer tracer) { -// TracerProviderHelper.global(tracer); -// } -// -// /** -// * Whether this tracer is enabled or not. -// * A no op tracer is disabled. -// * -// * @return {@code true} if this tracer is enabled -// */ -// boolean enabled(); -// -// /** -// * A new span builder to construct {@link io.helidon.tracing.Span}. -// * -// * @param name name of the operation -// * @return a new span builder -// */ -// Span.Builder spanBuilder(String name); -// -// /** -// * Extract parent span context from inbound request, such as from HTTP headers. -// * -// * @param headersProvider provider of headers -// * @return span context of inbound parent span, or empty optional if no span context can be found -// */ -// Optional extract(HeaderProvider headersProvider); -// -// /** -// * Inject current span as a parent for outbound request, such as when invoking HTTP request from a client. -// * -// * @param spanContext current span context -// * @param inboundHeadersProvider provider of inbound headers, may be {@link HeaderProvider#empty()} or headers from original -// * request (if any) -// * @param outboundHeadersConsumer consumer of headers that should be propagated to remote endpoint -// */ -// void inject(SpanContext spanContext, HeaderProvider inboundHeadersProvider, HeaderConsumer outboundHeadersConsumer); -// -// /** -// * Access the underlying tracer by specific type. -// * This is a dangerous operation that will succeed only if the tracer is of expected type. This practically -// * removes abstraction capabilities of this API. -// * -// * @param tracerClass type to access -// * @return instance of the tracer -// * @param type of the tracer -// * @throws java.lang.IllegalArgumentException in case the tracer cannot provide the expected type -// */ -// default T unwrap(Class tracerClass) { -// try { -// return tracerClass.cast(this); -// } catch (ClassCastException e) { -// throw new IllegalArgumentException("This tracer is not compatible with " + tracerClass.getName()); -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java deleted file mode 100644 index 9515df93034..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java +++ /dev/null @@ -1,244 +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.pico.builder.config.fakes.config; - -import java.util.Map; - -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka TracingConfig. - * - * Tracing configuration that contains traced components (such as WebServer, Security) and their traced spans and span logs. - * Spans can be renamed through configuration, components, spans and span logs may be disabled through this configuration. - */ -@ConfigBean(key = "tracing") -public interface FakeTracingConfig extends FakeTraceableConfig { -// /** -// * Traced config that is enabled for all components, spans and logs. -// */ -// FakeTracingConfig ENABLED = FakeTracingConfig.builder().build(); -// /** -// * Traced conifg that is disabled for all components, spans and logs. -// */ -// FakeTracingConfig DISABLED = FakeTracingConfig.builder().enabled(false).build(); - -// /** -// * A new traced configuration. -// * -// * @param name name of this configuration, when created using {@link FakeTracingConfig.Builder}, -// * the name is {@code helidon} -// */ -// protected FakeTracingConfig(String name) { -// super(name); -// } -// -// /** -// * Configuration of a traced component. -// * -// * @param componentName name of the component -// * @return component tracing configuration or empty if defaults should be used -// */ -// protected abstract Optional getComponent(String componentName); -// -// /** -// * Configuration of a traced component. -// * -// * @param componentName name of the component -// * @return component tracing configuration if configured, or an enabled component configuration -// */ -// public ComponentTracingConfig component(String componentName) { -// return component(componentName, true); -// } - - @Singular("component") // Builder::addComponent(String component); Impl::getComponent(String component); - Map components(); - -// /** -// * Configuration of a traced component. -// * -// * @param componentName name of the component -// * @param enabledByDefault whether the component should be enabled or disabled in case it is not configured -// * @return component tracing configuration if configured, or an enabled/disabled component configuration depending on -// * {@code enabledByDefault} -// */ -// public ComponentTracingConfig component(String componentName, boolean enabledByDefault) { -// if (enabled()) { -// return getComponent(componentName) -// .orElseGet(() -> enabledByDefault ? ComponentTracingConfig.ENABLED : ComponentTracingConfig.DISABLED); -// } -// -// return ComponentTracingConfig.DISABLED; -// } -// -// @Override -// public String toString() { -// return "TracingConfig(" + name() + ")"; -// } -// -// /** -// * Create new tracing configuration based on the provided config. -// * -// * @param config configuration of tracing -// * @return tracing configuration -// */ -// public static FakeTracingConfig create(Config config) { -// return builder().config(config).build(); -// } -// -// /** -// * A fluent API builder for tracing configuration. -// * @return a new builder instance -// */ -// public static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Merge two configurations together. -// * The result will combine configuration from both configurations. In case -// * of conflicts, the {@code newer} wins. -// * -// * @param older older instance to merge -// * @param newer newer (more significant) instance to merge -// * @return a new configuration combining odler and newer -// */ -// public static FakeTracingConfig merge(FakeTracingConfig older, FakeTracingConfig newer) { -// return new FakeTracingConfig(newer.name()) { -// @Override -// public Optional getComponent(String componentName) { -// Optional newerComponent = newer.getComponent(componentName); -// Optional olderComponent = older.getComponent(componentName); -// -// // both configured -// if (newerComponent.isPresent() && olderComponent.isPresent()) { -// return Optional.of(ComponentTracingConfig.merge(olderComponent.get(), newerComponent.get())); -// } -// -// // only newer configured -// if (newerComponent.isPresent()) { -// return newerComponent; -// } -// -// // only older configured -// return olderComponent; -// } -// -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// }; -// } -// -// /** -// * Return configuration of a specific span. -// * This is a shortcut method to {@link #component(String)} and -// * {@link ComponentTracingConfig#span(String)}. -// * -// * @param component component, such as "web-server", "security" -// * @param spanName name of the span, such as "HTTP Request", "security:atn" -// * @return configuration of the span if present in this traced system configuration -// */ -// public SpanTracingConfig spanConfig(String component, String spanName) { -// return component(component).span(spanName); -// } - -// /** -// * Fluent API builder for {@link FakeTracingConfig}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final Map components = new HashMap<>(); -// private Optional enabled = Optional.empty(); -// -// private Builder() { -// } -// -// @Override -// public FakeTracingConfig build() { -// return new RootTracingConfig("helidon", new HashMap<>(components), enabled); -// } -// -// /** -// * Update this builder from configuration. -// * -// * @param config Config with tracing configuration -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// Config compConfig = config.get("components"); -// compConfig.asNodeList() -// .ifPresent(compList -> { -// compList.forEach(componentConfig -> addComponent(ComponentTracingConfig.create(componentConfig.name(), -// componentConfig))); -// }); -// -// return this; -// } -// -// /** -// * Add a traced component configuration. -// * -// * @param component configuration of this component's tracing -// * @return updated builder instance -// */ -// public Builder addComponent(ComponentTracingConfig component) { -// components.put(component.name(), component); -// return this; -// } -// -// /** -// * Whether overall tracing is enabled. -// * If tracing is disabled on this level, all traced components and spans are disabled - even if explicitly configured -// * as enabled. -// * -// * @param enabled set to {@code false} to disable tracing for any component and span -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// } -// -// static final class RootTracingConfig extends FakeTracingConfig { -// private final Map components; -// private final Optional enabled; -// -// RootTracingConfig(String name, -// Map components, -// Optional enabled) { -// super(name); -// this.components = components; -// this.enabled = enabled; -// } -// -// @Override -// public Optional getComponent(String componentName) { -// return Optional.ofNullable(components.get(componentName)); -// } -// -// @Override -// public Optional isEnabled() { -// return enabled; -// } -// -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java deleted file mode 100644 index 5f1213c1484..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java +++ /dev/null @@ -1,438 +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.pico.builder.config.fakes.config; - -import java.security.SecureRandom; -import java.util.Collection; -import java.util.Random; -import java.util.Set; - -import javax.net.ssl.SSLContext; - -import io.helidon.common.LazyValue; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka WebServerTls. - * - * A class wrapping transport layer security (TLS) configuration for - * WebServer sockets. - */ -@ConfigBean -public interface FakeWebServerTlsConfig { - String PROTOCOL = "TLS"; - // secure random cannot be stored in native image, it must be initialized at runtime - LazyValue RANDOM = LazyValue.create(SecureRandom::new); - - /** - * This constant is a context classifier for the x509 client certificate if it is present. Callers may use this - * constant to lookup the client certificate associated with the current request context. - */ - String CLIENT_X509_CERTIFICATE = FakeWebServerTlsConfig.class.getName() + ".client-x509-certificate"; - -// private final Set enabledTlsProtocols; -// private final Set cipherSuite; -// private final SSLContext sslContext; -// private final boolean enabled; -// private final ClientAuthentication clientAuth; -// -// private FakeWebServerTlsConfigBean(Builder builder) { -// this.enabledTlsProtocols = Set.copyOf(builder.enabledTlsProtocols); -// this.cipherSuite = builder.cipherSuite; -// this.sslContext = builder.sslContext; -// this.enabled = (null != sslContext); -// this.clientAuth = builder.clientAuth; -// } -// -// /** -// * A fluent API builder for {@link FakeWebServerTlsConfigBean}. -// * -// * @return a new builder instance -// */ -// public static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Create TLS configuration from config. -// * -// * @param config located on the node of the tls configuration (usually this is {@code ssl}) -// * @return a new TLS configuration -// */ -// public static FakeWebServerTlsConfigBean create(Config config) { -// return builder().config(config).build(); -// } -// - - Collection enabledTlsProtocols(); -// { -// return enabledTlsProtocols; -// } -// - - SSLContext sslContext(); -// { -// return sslContext; -// } - -// ClientAuthentication clientAuth() { -// return clientAuth; -// } - - @Singular("cipher") - Set cipherSuite(); -// { -// return cipherSuite; -// } - - /** - * Whether this TLS config has security enabled (and the socket is going to be - * protected by one of the TLS protocols), or no (and the socket is going to be plain). - * - * @return {@code true} if this configuration represents a TLS configuration, {@code false} for plain configuration - */ - boolean enabled(); -// { -// return enabled; -// } -// -// /** -// * Fluent API builder for {@link FakeWebServerTlsConfigBean}. -// */ -// @Configured -// public static class Builder implements io.helidon.common.Builder { -// private final Set enabledTlsProtocols = new HashSet<>(); -// -// private SSLContext sslContext; -// private FakeKeyConfig privateKeyConfig; -// private FakeKeyConfig trustConfig; -// private long sessionCacheSize; -// private long sessionTimeoutSeconds; -// -// private boolean enabled; -// private Boolean explicitEnabled; -// private ClientAuthentication clientAuth; -// private Set cipherSuite = Set.of(); -// -// private Builder() { -// clientAuth = ClientAuthentication.NONE; -// } -// -// @Override -// public FakeWebServerTlsConfigBean build() { -// boolean enabled; -// -// if (null == explicitEnabled) { -// enabled = this.enabled; -// } else { -// enabled = explicitEnabled; -// } -// -// if (!enabled) { -// this.sslContext = null; -// // ssl is disabled -// return new FakeWebServerTlsConfigBean(this); -// } -// -// if (null == sslContext) { -// // no explicit ssl context, build it using private key and trust store -// sslContext = newSSLContext(); -// } -// -// return new FakeWebServerTlsConfigBean(this); -// } -// -// /** -// * Update this builder from configuration. -// * -// * @param config config on the node of SSL configuration -// * @return this builder -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// -// if (explicitEnabled != null && !explicitEnabled) { -// return this; -// } -// -// config.get("client-auth").asString().ifPresent(this::clientAuth); -// config.get("private-key") -// .ifExists(it -> privateKey(FakeKeyConfig.create(it))); -// -// config.get("trust") -// .ifExists(it -> trust(FakeKeyConfig.create(it))); -// -// config.get("protocols").asList(String.class).ifPresent(this::enabledProtocols); -// config.get("session-cache-size").asLong().ifPresent(this::sessionCacheSize); -// config.get("cipher-suite").asList(String.class).ifPresent(this::allowedCipherSuite); -// DeprecatedConfig.get(config, "session-timeout-seconds", "session-timeout") -// .asLong() -// .ifPresent(this::sessionTimeoutSeconds); -// -// return this; -// } -// -// private void clientAuth(String it) { -// clientAuth(ClientAuthentication.valueOf(it.toUpperCase())); -// } -// -// /** -// * Configures whether client authentication will be required or not. -// * -// * @param clientAuth client authentication -// * @return this builder -// */ -// @ConfiguredOption("none") -// public Builder clientAuth(ClientAuthentication clientAuth) { -// this.clientAuth = Objects.requireNonNull(clientAuth); -// return this; -// } -// -// /** -// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then -// * the server enforces an SSL communication. -// * -// * @param context a SSL context to use -// * @return this builder -// */ -// public Builder sslContext(SSLContext context) { -// this.enabled = true; -// this.sslContext = context; -// return this; -// } -// -// /** -// * Configures the TLS protocols to enable with the server socket. -// * @param protocols protocols to enable, if empty, enables defaults -// * -// * @return this builder -// * @throws java.lang.NullPointerException in case the protocols is null -// */ -// public Builder enabledProtocols(String... protocols) { -// return enabledProtocols(Arrays.asList(Objects.requireNonNull(protocols))); -// } -// -// /** -// * Configures the TLS protocols to enable with the server socket. -// * -// * @param protocols protocols to enable, if empty enables -// * the default protocols -// * @return this builder -// * @throws java.lang.NullPointerException in case the protocols is null -// */ -// public Builder enabledProtocols(Collection protocols) { -// Objects.requireNonNull(protocols); -// -// this.enabledTlsProtocols.clear(); -// this.enabledTlsProtocols.addAll(protocols); -// return this; -// } -// -// /** -// * Configure private key to use for SSL context. -// * -// * @param privateKeyConfig the required private key configuration parameter -// * @return this builder -// */ -// @ConfiguredOption(required = true) -// public Builder privateKey(FakeKeyConfig privateKeyConfig) { -// // setting private key, need to reset ssl context -// this.enabled = true; -// this.sslContext = null; -// this.privateKeyConfig = Objects.requireNonNull(privateKeyConfig); -// return this; -// } -// -// /** -// * Configure private key to use for SSL context. -// * -// * @param privateKeyConfigBuilder the required private key configuration parameter -// * @return this builder -// */ -// public Builder privateKey(Supplier privateKeyConfigBuilder) { -// return privateKey(privateKeyConfigBuilder.get()); -// } -// -// /** -// * Set the trust key configuration to be used to validate certificates. -// * -// * @param trustConfig the trust configuration -// * @return this builder -// */ -// @ConfiguredOption -// public Builder trust(FakeKeyConfig trustConfig) { -// // setting explicit trust, need to reset ssl context -// this.enabled = true; -// this.sslContext = null; -// this.trustConfig = Objects.requireNonNull(trustConfig); -// return this; -// } -// -// /** -// * Set the trust key configuration to be used to validate certificates. -// * -// * @param trustConfigBuilder the trust configuration builder -// * @return this builder -// */ -// public Builder trust(Supplier trustConfigBuilder) { -// return trust(trustConfigBuilder.get()); -// } -// -// /** -// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the -// * default value. -// * -// * @param sessionCacheSize the session cache size -// * @return this builder -// */ -// @ConfiguredOption -// public Builder sessionCacheSize(long sessionCacheSize) { -// this.sessionCacheSize = sessionCacheSize; -// return this; -// } -// -// /** -// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the -// * default value. -// * -// * @param sessionTimeout the session timeout -// * @return this builder -// */ -// @ConfiguredOption -// public Builder sessionTimeoutSeconds(long sessionTimeout) { -// this.sessionTimeoutSeconds = sessionTimeout; -// return this; -// } -// -// /** -// * Set the timeout for the cached SSL session objects. {@code 0} to use the -// * default value. -// * -// * @param timeout the session timeout amount -// * @param unit the session timeout time unit -// * @return this builder -// */ -// public Builder sessionTimeout(long timeout, TimeUnit unit) { -// this.sessionTimeoutSeconds = unit.toSeconds(timeout); -// return this; -// } -// -// /** -// * Set allowed cipher suite. If an empty collection is set, an exception is thrown since -// * it is required to support at least some ciphers. -// * -// * @param cipherSuite allowed cipher suite -// * @return an updated builder -// */ -// @ConfiguredOption(key = "cipher-suite") -// public Builder allowedCipherSuite(List cipherSuite) { -// Objects.requireNonNull(cipherSuite); -// if (cipherSuite.isEmpty()) { -// throw new IllegalStateException("Allowed cipher suite has to have at least one cipher specified"); -// } -// this.cipherSuite = Set.copyOf(cipherSuite); -// return this; -// } -// -// /** -// * Whether the TLS config should be enabled or not. -// * -// * @param enabled configure to {@code false} to disable SSL context (and SSL support on the server) -// * @return this builder -// */ -// @ConfiguredOption(description = "Can be used to disable TLS even if keys are configured.", value = "true") -// public Builder enabled(boolean enabled) { -// this.enabled = enabled; -// this.explicitEnabled = enabled; -// return this; -// } -// -// private SSLContext newSSLContext() { -// try { -// if (null == privateKeyConfig) { -// throw new IllegalStateException("Private key must be configured when SSL is enabled."); -// } -// KeyManagerFactory kmf = buildKmf(this.privateKeyConfig); -// TrustManagerFactory tmf = buildTmf(this.trustConfig); -// -// // Initialize the SSLContext to work with our key managers. -// SSLContext ctx = SSLContext.getInstance(PROTOCOL); -// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); -// -// SSLSessionContext sessCtx = ctx.getServerSessionContext(); -// if (sessionCacheSize > 0) { -// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); -// } -// if (this.sessionTimeoutSeconds > 0) { -// sessCtx.setSessionTimeout((int) Math.min(sessionTimeoutSeconds, Integer.MAX_VALUE)); -// } -// return ctx; -// } catch (IOException | GeneralSecurityException e) { -// throw new IllegalStateException("Failed to build server SSL Context!", e); -// } -// } -// -// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { -// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); -// if (algorithm == null) { -// algorithm = "SunX509"; -// } -// -// byte[] passwordBytes = new byte[64]; -// RANDOM.get().nextBytes(passwordBytes); -// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// ks.setKeyEntry("key", -// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), -// password, -// privateKeyConfig.certChain().toArray(new Certificate[0])); -// -// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); -// kmf.init(ks, password); -// -// return kmf; -// } -// -// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) -// throws IOException, GeneralSecurityException { -// List certs; -// -// if (trustConfig == null) { -// certs = List.of(); -// } else { -// certs = trustConfig.certs(); -// } -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// -// int i = 1; -// for (X509Certificate cert : certs) { -// ks.setCertificateEntry(String.valueOf(i), cert); -// i++; -// } -// -// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); -// tmf.init(ks); -// return tmf; -// } -// } -// -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java deleted file mode 100644 index c674fed80e4..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java +++ /dev/null @@ -1,201 +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.pico.builder.config.fakes.config; - -import java.util.Random; - -import io.helidon.pico.builder.Builder; - -/** - * aka SSLContextBuilder. - */ -@Builder -public interface SSLContextConfig { - - String PROTOCOL = "TLS"; - Random RANDOM = new Random(); - -// private FakeKeyConfig privateKeyConfig; -// private FakeKeyConfig trustConfig; -// private long sessionCacheSize; -// private long sessionTimeout; -// -// private SSLContextConfig() { -// } -// - -// /** -// * Creates a builder of the {@link javax.net.ssl.SSLContext}. -// * -// * @param privateKeyConfig the required private key configuration parameter -// * @return this builder -// */ -// public static SSLContextConfig create(FakeKeyConfig privateKeyConfig) { -// return new SSLContextConfig().privateKeyConfig(privateKeyConfig); -// } - -// /** -// * Creates {@link javax.net.ssl.SSLContext} from the provided configuration. -// * -// * @param sslConfig the ssl configuration -// * @return a built {@link javax.net.ssl.SSLContext} -// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or -// * a {@link java.security.GeneralSecurityException} -// */ -// static SSLContext create(Config sslConfig) { -// return new SSLContextConfig().privateKeyConfig(FakeKeyConfig.create(sslConfig.get("private-key"))) -// .sessionCacheSize(sslConfig.get("session-cache-size").asInt().orElse(0)) -// .sessionTimeout(sslConfig.get("session-timeout").asInt().orElse(0)) -// .trustConfig(FakeKeyConfig.create(sslConfig.get("trust"))) -// .build(); -// } -// -// private SSLContextConfig privateKeyConfig(FakeKeyConfig privateKeyConfig) { -// this.privateKeyConfig = privateKeyConfig; -// return this; -// } - - FakeKeyConfig privateKeyConfig(); - -// -// /** -// * Set the trust key configuration to be used to validate certificates. -// * -// * @param trustConfig the trust configuration -// * @return an updated builder -// */ -// public SSLContextConfig trustConfig(FakeKeyConfig trustConfig) { -// this.trustConfig = trustConfig; -// return this; -// } - - FakeKeyConfig trustConfig(); - -// /** -// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the -// * default value. -// * -// * @param sessionCacheSize the session cache size -// * @return an updated builder -// */ -// public SSLContextConfig sessionCacheSize(long sessionCacheSize) { -// this.sessionCacheSize = sessionCacheSize; -// return this; -// } - - long sessionCacheSize(); - -// /** -// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the -// * default value. -// * -// * @param sessionTimeout the session timeout -// * @return an updated builder -// */ -// public SSLContextConfig sessionTimeout(long sessionTimeout) { -// this.sessionTimeout = sessionTimeout; -// return this; -// } - - long sessionTimeout(); - -// /** -// * Create new {@code {@link javax.net.ssl.SSLContext}} instance with configured settings. -// * -// * @return the SSL Context built instance -// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or -// * a {@link java.security.GeneralSecurityException} -// */ -// public SSLContext build() { -// Objects.requireNonNull(privateKeyConfig, "The private key config must be set!"); -// -// try { -// return newSSLContext(privateKeyConfig, trustConfig, sessionCacheSize, sessionTimeout); -// } catch (IOException | GeneralSecurityException e) { -// throw new IllegalStateException("Building of the SSLContext of unsuccessful!", e); -// } -// } - -// private static SSLContext newSSLContext(FakeKeyConfig privateKeyConfig, -// FakeKeyConfig trustConfig, -// long sessionCacheSize, -// long sessionTimeout) -// throws IOException, GeneralSecurityException { -// KeyManagerFactory kmf = buildKmf(privateKeyConfig); -// TrustManagerFactory tmf = buildTmf(trustConfig); -// -// // Initialize the SSLContext to work with our key managers. -// SSLContext ctx = SSLContext.getInstance(PROTOCOL); -// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); -// -// SSLSessionContext sessCtx = ctx.getServerSessionContext(); -// if (sessionCacheSize > 0) { -// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); -// } -// if (sessionTimeout > 0) { -// sessCtx.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE)); -// } -// return ctx; -// } -// -// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { -// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); -// if (algorithm == null) { -// algorithm = "SunX509"; -// } -// -// byte[] passwordBytes = new byte[64]; -// RANDOM.nextBytes(passwordBytes); -// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// ks.setKeyEntry("key", -// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), -// password, -// privateKeyConfig.certChain().toArray(new Certificate[0])); -// -// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); -// kmf.init(ks, password); -// -// return kmf; -// } -// -// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) -// throws IOException, GeneralSecurityException { -// List certs; -// -// if (trustConfig == null) { -// certs = List.of(); -// } else { -// certs = trustConfig.certs(); -// } -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// -// int i = 1; -// for (X509Certificate cert : certs) { -// ks.setCertificateEntry(String.valueOf(i), cert); -// i++; -// } -// -// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); -// tmf.init(ks); -// return tmf; -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java index 2636622a275..6a260de4a14 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java @@ -14,23 +14,40 @@ * limitations under the License. */ -package io.helidon.pico.builder.config.test.testsubjects; +package io.helidon.pico.builder.config.testsubjects; import java.util.Map; import io.helidon.config.metadata.ConfiguredOption; import io.helidon.pico.builder.config.ConfigBean; -import io.helidon.pico.builder.config.testsubjects.CommonConfig; +/** + * For testing purpose. + */ @ConfigBean(drivesActivation = false) public interface ClientConfig extends CommonConfig { + /** + * For testing purpose. + * + * @return for testing purposes + */ @ConfiguredOption("default") @Override String name(); + /** + * For testing purpose. + * + * @return for testing purposes + */ int serverPort(); + /** + * For testing purpose. + * + * @return for testing purposes + */ Map headers(); } diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java index 8c6d70d2d86..fcd20417939 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java @@ -21,16 +21,39 @@ import io.helidon.config.metadata.ConfiguredOption; import io.helidon.pico.builder.config.ConfigBean; +/** + * For testing purpose. + */ @ConfigBean public interface CommonConfig { + /** + * For testing purpose. + * + * @return for testing purposes + */ String name(); + /** + * For testing purpose. + * + * @return for testing purposes + */ @ConfiguredOption(required = true) int port(); + /** + * For testing purpose. + * + * @return for testing purposes + */ List cipherSuites(); + /** + * For testing purpose. + * + * @return for testing purposes + */ char[] pwd(); } diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java index 9dcd7bf600e..f5a569a08ee 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java @@ -21,13 +21,26 @@ import io.helidon.config.metadata.ConfiguredOption; import io.helidon.pico.builder.config.ConfigBean; +/** + * For testing purpose. + */ @ConfigBean(atLeastOne = true) public interface ServerConfig extends CommonConfig { + /** + * For testing purpose. + * + * @return for testing purposes + */ @ConfiguredOption("default") @Override String name(); + /** + * For testing purpose. + * + * @return for testing purposes + */ Optional description(); } diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/package-info.java similarity index 78% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java rename to pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/package-info.java index 238f795421a..0c9849e207d 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/package-info.java @@ -14,13 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.config.fakes.config; - -public enum FakeNettyClientAuth { - NONE, - OPTIONAL, - REQUIRE; - - private FakeNettyClientAuth() { - } -} +/** + * ConfigBean test subjects. + */ +package io.helidon.pico.builder.config.testsubjects; diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracer.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracer.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/WebServer.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/WebServer.java From 743b779167faeefec96c3795eb4346ef0e198d48 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 22 Nov 2022 10:47:57 -0500 Subject: [PATCH 03/36] Promote ConfigMapper and ConfigMapperProvider to common level SPI. Then extend ConfigBeanMapper to be a specialization of ConfigMapperProvider --- .../helidon/common/config/ConfigHolder.java | 4 +- .../common/config/spi/ConfigMapper.java | 42 +++++++++++++++++++ .../config/spi/ConfigMapperProvider.java | 40 ++++++++++++++++++ common/config/src/main/java/module-info.java | 1 + config/config/etc/spotbugs/exclude.xml | 10 +++++ .../io/helidon/config/spi/ConfigMapper.java | 7 +++- .../config/spi/ConfigMapperProvider.java | 5 ++- config/config/src/main/java/module-info.java | 5 +-- .../pico/builder/config/package-info.java | 2 +- .../builder/config/spi/ConfigBeanMapper.java | 10 ++--- .../config/spi/ConfigBeanMapperHolder.java | 2 +- 11 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java diff --git a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java index d84dc6e3b59..753c66fefb7 100644 --- a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java +++ b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java @@ -33,7 +33,7 @@ * (2) programmatically via the {@link #config(io.helidon.common.config.Config)} method. The {@link #config()} method will * apply the following strategy to resolve and cache the global config instance: *

    - *
  1. if the instance is already been established and cached then use it.
  2. + *
  3. if the instance has already been established and cached then use it.
  4. *
  5. if the instance has programmatically been set then use it - this is the same as the cached instance.
  6. *
  7. use the service loader to resolve the config instance, and if found then cache it.
  8. *
@@ -42,7 +42,7 @@ * method. *

* Note that this class is not thread safe. If the global configuration must be set programmatically then it should therefore - * be set on the main thread typically early in the jvm lifecycle. + * be set on the main thread, and typically early in the jvm lifecycle. * * @see io.helidon.common.config.spi.ConfigProvider */ diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java new file mode 100644 index 00000000000..5dffb4e8b7d --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java @@ -0,0 +1,42 @@ +/* + * 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.common.config.spi; + +import io.helidon.common.config.Config; +import io.helidon.common.config.ConfigException; + +/** + * Config mapper is provided to {@link ConfigMapperProvider} to help transformation of + * complex structures. + * + * @param the Config type + */ +@FunctionalInterface +public interface ConfigMapper { + + /** + * Converts the specified {@code Config} node to the target type. + * + * @param config config node to be transformed + * @param type type to which the config node is to be transformed + * @param type to which the config node is to be transformed + * @return transformed value of type {@code T}; never returns {@code null} + * @throws io.helidon.common.config.ConfigException if any issues occur in mapping + */ + T map(C config, Class type) throws ConfigException; + +} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java new file mode 100644 index 00000000000..3ec6a715764 --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java @@ -0,0 +1,40 @@ +/* + * 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.common.config.spi; + +import java.util.Map; +import java.util.function.Function; + +import io.helidon.common.config.Config; + +/** + * Provides mapping functions that convert a {@code Config} + * subtree to specific Java types. + * + * @param the Config type + */ +@FunctionalInterface +public interface ConfigMapperProvider { + + /** + * Returns a map of mapper functions associated with appropriate target type ({@code Class}. + * + * @return a map of config mapper functions, never {@code null} + */ + Map, Function> mappers(); + +} diff --git a/common/config/src/main/java/module-info.java b/common/config/src/main/java/module-info.java index 86500ceda0f..74bcf4c599e 100644 --- a/common/config/src/main/java/module-info.java +++ b/common/config/src/main/java/module-info.java @@ -20,6 +20,7 @@ module io.helidon.common.config { requires io.helidon.common; + uses io.helidon.common.config.spi.ConfigMapperProvider; uses io.helidon.common.config.spi.ConfigProvider; exports io.helidon.common.config; diff --git a/config/config/etc/spotbugs/exclude.xml b/config/config/etc/spotbugs/exclude.xml index 5e1451958f9..535dd1c158c 100644 --- a/config/config/etc/spotbugs/exclude.xml +++ b/config/config/etc/spotbugs/exclude.xml @@ -103,5 +103,15 @@ + + + + + + + + + + diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java index b08d80456d5..067cf3768d4 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.helidon.config.spi; import java.lang.reflect.Type; @@ -26,7 +27,8 @@ * Config mapper is provided to {@link ConfigMapperProvider} to help transformation of * complex structures. */ -public interface ConfigMapper { +public interface ConfigMapper extends io.helidon.common.config.spi.ConfigMapper { + /** * Convert the specified {@code Config} node into the target type specified by {@link GenericType}. * You can use {@link GenericType#create(Type)} if needed to wrap a parametrized type. @@ -58,6 +60,7 @@ public interface ConfigMapper { * @throws ConfigMappingException in case the mapper fails to map the existing configuration value * to an instance of a given Java type */ + @Override T map(Config config, Class type) throws MissingValueException, ConfigMappingException; /** diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java index 86f8d140cef..d43eea3fce1 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. + * Copyright (c) 2017, 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. @@ -43,7 +43,7 @@ * @see Config.Builder#disableMapperServices() */ @FunctionalInterface -public interface ConfigMapperProvider { +public interface ConfigMapperProvider extends io.helidon.common.config.spi.ConfigMapperProvider { /** * Default priority of the mapper provider if registered by {@link Config.Builder} automatically. */ @@ -59,6 +59,7 @@ public interface ConfigMapperProvider { * @return a map of config mapper functions, never {@code null}, though this may return an empty map if * {@link #mapper(Class)} is used instead */ + @Override Map, Function> mappers(); /** diff --git a/config/config/src/main/java/module-info.java b/config/config/src/main/java/module-info.java index da42f7919f1..13ba3775edb 100644 --- a/config/config/src/main/java/module-info.java +++ b/config/config/src/main/java/module-info.java @@ -14,8 +14,6 @@ * limitations under the License. */ -import io.helidon.config.PropertiesConfigParser; - /** * Helidon SE Config module. * @@ -43,7 +41,8 @@ uses io.helidon.config.spi.PollingStrategyProvider; uses io.helidon.config.spi.ChangeWatcherProvider; - provides io.helidon.config.spi.ConfigParser with PropertiesConfigParser; + provides io.helidon.config.spi.ConfigParser + with io.helidon.config.PropertiesConfigParser; // needed when running with modules - to make private methods accessible opens io.helidon.config to weld.core.impl, io.helidon.microprofile.cdi; diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java index bf8cfa090f8..fa8c61aee55 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java @@ -15,6 +15,6 @@ */ /** - * Helidon Pico Config Builder API. + * Helidon Pico ConfigBean Builder API. */ package io.helidon.pico.builder.config; diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java index a71e423257d..c268a737b7c 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java @@ -17,24 +17,24 @@ package io.helidon.pico.builder.config.spi; import io.helidon.common.config.Config; +import io.helidon.common.config.spi.ConfigMapper; /** * Maps a {@link io.helidon.common.config.Config} instance to a newly created * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type instance. * - * @param the config bean type + * @param the config type */ -@FunctionalInterface -public interface ConfigBeanMapper { +public interface ConfigBeanMapper extends ConfigMapper { /** * Translate the provided configuration into the appropriate config bean for this service type. * * @param cfg the config * @param configBeanType the config bean type + * @param the config bean type * @return the config bean generated */ - CB toConfigBean(Config cfg, - Class configBeanType); + T map(T cfg, Class configBeanType); } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java index f287390a360..d27d863b003 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java @@ -46,7 +46,7 @@ private ConfigBeanMapperHolder() { * @return the config bean mapper */ @SuppressWarnings({"rawTypes", "unchecked"}) - public static Optional> configBeanMapperFor(Class configBeanType) { + public static Optional configBeanMapperFor(Class configBeanType) { return (Optional) INSTANCE.get(); } From 50f4ed43d79e7f7393b06baba9fe6a41ed4e1266 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 22 Nov 2022 11:11:05 -0500 Subject: [PATCH 04/36] A few tweaks over the last push. --- .../ConfigBeanBuilderValidatorProvider.java | 1 + .../builder/config/spi/ConfigBeanMapper.java | 4 ++- .../config/spi/ConfigBeanMapperProvider.java | 1 + .../config/spi/ConfigResolverProvider.java | 1 + pico/builder-config/tests/configbean/pom.xml | 32 ------------------- 5 files changed, 6 insertions(+), 33 deletions(-) diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java index ece42d72d74..43789b7c5c7 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java @@ -21,6 +21,7 @@ * * @see ConfigBeanBuilderValidatorHolder */ +@FunctionalInterface public interface ConfigBeanBuilderValidatorProvider { /** diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java index c268a737b7c..911938639ce 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java @@ -25,6 +25,7 @@ * * @param the config type */ +@FunctionalInterface public interface ConfigBeanMapper extends ConfigMapper { /** @@ -35,6 +36,7 @@ public interface ConfigBeanMapper extends ConfigMapper { * @param the config bean type * @return the config bean generated */ - T map(T cfg, Class configBeanType); + @Override + T map(C cfg, Class configBeanType); } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java index eac42ff3c4d..2c6b65cde3d 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java @@ -21,6 +21,7 @@ * * @see ConfigBeanMapperHolder */ +@FunctionalInterface public interface ConfigBeanMapperProvider { /** diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java index bc37b31eca9..3fa5c2d8a79 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java @@ -19,6 +19,7 @@ /** * Java {@link java.util.ServiceLoader} provider interface to find implementation of {@link ConfigResolver}. */ +@FunctionalInterface public interface ConfigResolverProvider { /** diff --git a/pico/builder-config/tests/configbean/pom.xml b/pico/builder-config/tests/configbean/pom.xml index 76648bbe2dc..5d542baa90e 100644 --- a/pico/builder-config/tests/configbean/pom.xml +++ b/pico/builder-config/tests/configbean/pom.xml @@ -101,41 +101,9 @@ helidon-pico-builder-config-processor ${helidon.version} - - - - - - - - - - - - - - - - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - From c5f03399fb2afc3d2b3def1304d84d694cec2031 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 22 Nov 2022 12:45:35 -0500 Subject: [PATCH 05/36] A few tweaks over the last push. --- config/config/etc/spotbugs/exclude.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config/etc/spotbugs/exclude.xml b/config/config/etc/spotbugs/exclude.xml index 535dd1c158c..2f8695941ca 100644 --- a/config/config/etc/spotbugs/exclude.xml +++ b/config/config/etc/spotbugs/exclude.xml @@ -106,12 +106,12 @@ - + - + From 1cd03c9e7277d04b3a468fd7f46b28da318caace Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Wed, 16 Nov 2022 16:19:48 -0800 Subject: [PATCH 06/36] Suppress false positives (#5450) --- etc/dependency-check-suppression.xml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/etc/dependency-check-suppression.xml b/etc/dependency-check-suppression.xml index ce3732b7ae9..b1674b71d2e 100644 --- a/etc/dependency-check-suppression.xml +++ b/etc/dependency-check-suppression.xml @@ -370,4 +370,30 @@ CVE-2022-34917 + + + + + ^pkg:maven/jakarta\.resource/jakarta\.resource\-api@.*$ + CVE-2022-45129 + + + + ^pkg:maven/org\.eclipse\.microprofile\.config/microprofile\-config\-api@.*$ + CVE-2022-45129 + + + + ^pkg:maven/org\.eclipse\.microprofile\.jwt/microprofile\-jwt\-auth\-api@.*$ + CVE-2022-45129 + + + + From dfee561621390828024a2238f41d7610a332fe2c Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 17 Nov 2022 20:34:15 +0100 Subject: [PATCH 07/36] Fix handling of optional whitespace at the beginning of headers. (#5441) --- .../java/io/helidon/common/buffers/Bytes.java | 4 + .../io/helidon/common/buffers/LazyString.java | 42 +++++++++++ .../common/buffers/LazyStringTest.java | 74 +++++++++++++++++++ .../helidon/common/http/HeaderValueLazy.java | 6 +- .../common/http/Http1HeadersParser.java | 24 +++--- 5 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 common/buffers/src/test/java/io/helidon/common/buffers/LazyStringTest.java diff --git a/common/buffers/src/main/java/io/helidon/common/buffers/Bytes.java b/common/buffers/src/main/java/io/helidon/common/buffers/Bytes.java index 379d8ef975b..f6ec7a596d1 100644 --- a/common/buffers/src/main/java/io/helidon/common/buffers/Bytes.java +++ b/common/buffers/src/main/java/io/helidon/common/buffers/Bytes.java @@ -64,6 +64,10 @@ public final class Bytes { * {@code %} byte. */ public static final byte PERCENT_BYTE = (byte) '%'; + /** + * Horizontal tabulator byte. + */ + public static final byte TAB_BYTE = (byte) '\t'; private Bytes() { } diff --git a/common/buffers/src/main/java/io/helidon/common/buffers/LazyString.java b/common/buffers/src/main/java/io/helidon/common/buffers/LazyString.java index 418064814cd..911e22b72e7 100644 --- a/common/buffers/src/main/java/io/helidon/common/buffers/LazyString.java +++ b/common/buffers/src/main/java/io/helidon/common/buffers/LazyString.java @@ -28,6 +28,7 @@ public class LazyString { private final Charset charset; private String stringValue; + private String owsLessValue; /** * New instance. @@ -57,6 +58,40 @@ public LazyString(byte[] buffer, Charset charset) { this.charset = charset; } + /** + * Strip optional whitespace(s) from beginning and end of the String. + * Defined by the HTTP specification, OWS is a sequence of zero to n space and/or horizontal tab characters. + * + * @return string without optional leading and trailing whitespaces + */ + public String stripOws() { + if (owsLessValue == null) { + int newOffset = offset; + int newLength = length; + for (int i = offset; i < offset + length; i++) { + if (isOws(buffer[i])) { + newOffset = i + 1; + newLength = length - (newOffset - offset); + } else { + // no more white space, go from the end now + break; + } + } + // now we need to go from the end of the string + for (int i = offset + length - 1; i > newOffset; i--) { + if (isOws(buffer[i])) { + newLength--; + } else { + break; + } + } + newLength = Math.max(newLength, 0); + owsLessValue = new String(buffer, newOffset, newLength, charset); + } + + return owsLessValue; + } + @Override public String toString() { if (stringValue == null) { @@ -64,4 +99,11 @@ public String toString() { } return stringValue; } + + private boolean isOws(byte aByte) { + return switch (aByte) { + case Bytes.SPACE_BYTE, Bytes.TAB_BYTE -> true; + default -> false; + }; + } } diff --git a/common/buffers/src/test/java/io/helidon/common/buffers/LazyStringTest.java b/common/buffers/src/test/java/io/helidon/common/buffers/LazyStringTest.java new file mode 100644 index 00000000000..e54eef6f174 --- /dev/null +++ b/common/buffers/src/test/java/io/helidon/common/buffers/LazyStringTest.java @@ -0,0 +1,74 @@ +/* + * 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.common.buffers; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class LazyStringTest { + @ParameterizedTest + @MethodSource("owsData") + void testOwsHandling(OwsTestData data) { + assertThat(data.string().stripOws(), is(data.expected())); + } + + private static Stream owsData() { + return Stream.of( + new OwsTestData(new LazyString("some-value".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString(" some-value".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("\tsome-value".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString(" some-value".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("\t\tsome-value".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString(" \tsome-value".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("some-value ".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("some-value\t".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("some-value ".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("some-value\t\t".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("some-value \t".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString(" some-value ".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("\tsome-value\t".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString(" some-value ".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString("\t\tsome-value\t\t".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString(" \tsome-value\t ".getBytes(US_ASCII), US_ASCII), "some-value"), + new OwsTestData(new LazyString(" \t\t ".getBytes(US_ASCII), US_ASCII), ""), + new OwsTestData(new LazyString(" \t\r\t ".getBytes(US_ASCII), US_ASCII), "\r") + ); + } + + record OwsTestData(LazyString string, String expected) { + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + + for (char c : string().toString().toCharArray()) { + switch (c) { + case '\t' -> result.append("\\t"); + case '\r' -> result.append("\\r"); + default -> result.append(c); + } + } + + return "\"" + result + "\""; + } + } +} diff --git a/common/http/src/main/java/io/helidon/common/http/HeaderValueLazy.java b/common/http/src/main/java/io/helidon/common/http/HeaderValueLazy.java index 21a7570618c..a20b989c2f3 100644 --- a/common/http/src/main/java/io/helidon/common/http/HeaderValueLazy.java +++ b/common/http/src/main/java/io/helidon/common/http/HeaderValueLazy.java @@ -35,7 +35,7 @@ class HeaderValueLazy extends HeaderValueBase { public Http.HeaderValueWriteable addValue(String value) { if (values == null) { values = new ArrayList<>(2); - values.add(this.value.toString()); + values.add(this.value.stripOws()); } values.add(value); return this; @@ -43,14 +43,14 @@ public Http.HeaderValueWriteable addValue(String value) { @Override public String value() { - return value.toString(); + return value.stripOws(); } @Override public List allValues() { if (values == null) { values = new ArrayList<>(2); - values.add(value.toString()); + values.add(value.stripOws()); } return values; } diff --git a/common/http/src/main/java/io/helidon/common/http/Http1HeadersParser.java b/common/http/src/main/java/io/helidon/common/http/Http1HeadersParser.java index aa0111271d6..b5e29d7383e 100644 --- a/common/http/src/main/java/io/helidon/common/http/Http1HeadersParser.java +++ b/common/http/src/main/java/io/helidon/common/http/Http1HeadersParser.java @@ -27,10 +27,13 @@ */ public final class Http1HeadersParser { // TODO expand set of fastpath headers - private static final byte[] HD_HOST = (HeaderEnum.HOST.defaultCase() + ": ").getBytes(StandardCharsets.UTF_8); - private static final byte[] HD_ACCEPT = (HeaderEnum.ACCEPT.defaultCase() + ": ").getBytes(StandardCharsets.UTF_8); + private static final byte[] HD_HOST = (HeaderEnum.HOST.defaultCase() + ":").getBytes(StandardCharsets.UTF_8); + private static final byte[] HD_ACCEPT = (HeaderEnum.ACCEPT.defaultCase() + ":").getBytes(StandardCharsets.UTF_8); private static final byte[] HD_CONNECTION = - (HeaderEnum.CONNECTION.defaultCase() + ": ").getBytes(StandardCharsets.UTF_8); + (HeaderEnum.CONNECTION.defaultCase() + ":").getBytes(StandardCharsets.UTF_8); + + private static final byte[] HD_USER_AGENT = + (HeaderEnum.USER_AGENT.defaultCase() + ":").getBytes(StandardCharsets.UTF_8); private Http1HeadersParser() { } @@ -53,7 +56,7 @@ public static WritableHeaders readHeaders(DataReader reader, int maxHeadersSi return headers; } - Http.HeaderName header = readHeaderName(reader, headers, maxLength, validate); + Http.HeaderName header = readHeaderName(reader, maxLength, validate); maxLength -= header.defaultCase().length() + 2; int eol = reader.findNewLine(maxLength); if (eol == maxLength) { @@ -72,7 +75,6 @@ public static WritableHeaders readHeaders(DataReader reader, int maxHeadersSi } private static Http.HeaderName readHeaderName(DataReader reader, - WritableHeaders headers, int maxLength, boolean validate) { switch (reader.lookup()) { @@ -94,6 +96,12 @@ private static Http.HeaderName readHeaderName(DataReader reader, return HeaderEnum.CONNECTION; } } + case (byte) 'U' -> { + if (reader.startsWith(HD_USER_AGENT)) { + reader.skip(HD_USER_AGENT.length); + return HeaderEnum.USER_AGENT; + } + } default -> { } } @@ -109,10 +117,8 @@ private static Http.HeaderName readHeaderName(DataReader reader, HttpToken.validate(headerName); } Http.HeaderName header = Http.Header.create(headerName); - reader.skip(1); - if (Bytes.SPACE_BYTE != reader.read()) { - throw new IllegalArgumentException("Invalid header, space not after colon: " + reader.debugDataHex()); - } + reader.skip(1); // skip the colon character + return header; } } From f77e47a1c11d240586f9126f41c1b6e2c68727a6 Mon Sep 17 00:00:00 2001 From: Keith Lustria <34235093+klustria@users.noreply.github.com> Date: Fri, 18 Nov 2022 10:12:15 -0800 Subject: [PATCH 08/36] NullPointerException when there is an illegal character in the request (#5470) (#5472) --- .../io/helidon/reactive/webserver/ForwardingHandler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/ForwardingHandler.java b/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/ForwardingHandler.java index 55c02b34a8e..8062051a836 100644 --- a/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/ForwardingHandler.java +++ b/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/ForwardingHandler.java @@ -340,6 +340,9 @@ private boolean channelReadHttpRequest(ChannelHandlerContext ctx, Context reques // New request ID long requestId = REQUEST_ID_GENERATOR.incrementAndGet(); + + requestEntityAnalyzed = new CompletableFuture<>(); + // If a problem with the request URI, return 400 response BareRequestImpl bareRequest; try { @@ -395,8 +398,6 @@ private boolean channelReadHttpRequest(ChannelHandlerContext ctx, Context reques prevRequestFuture = null; } - requestEntityAnalyzed = new CompletableFuture<>(); - //If the keep alive is not set, we know we will be closing the connection if (!HttpUtil.isKeepAlive(requestContext.request())) { this.requestEntityAnalyzed.complete(ChannelFutureListener.CLOSE); From b5747c8831b5f684fec9400db05116e9765d0971 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Mon, 21 Nov 2022 00:21:21 +0100 Subject: [PATCH 09/36] Error handling support in HTTP for Nima WebServer. (#5436) --- .../integration/server/ErrorHandlingTest.java | 169 ++++++++++++++ nima/webserver/webserver/pom.xml | 15 ++ .../{Executable.java => ErrorHandler.java} | 19 +- .../nima/webserver/http/ErrorHandlers.java | 91 +++++++- .../helidon/nima/webserver/http/Filters.java | 16 +- .../nima/webserver/http/HttpRouting.java | 30 ++- .../webserver/http/ErrorHandlersTest.java | 210 ++++++++++++++++++ 7 files changed, 520 insertions(+), 30 deletions(-) create mode 100644 nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ErrorHandlingTest.java rename nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/{Executable.java => ErrorHandler.java} (55%) create mode 100644 nima/webserver/webserver/src/test/java/io/helidon/nima/webserver/http/ErrorHandlersTest.java diff --git a/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ErrorHandlingTest.java b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ErrorHandlingTest.java new file mode 100644 index 00000000000..007af2ad677 --- /dev/null +++ b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ErrorHandlingTest.java @@ -0,0 +1,169 @@ +/* + * 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.nima.tests.integration.server; + +import io.helidon.common.http.Http; +import io.helidon.nima.testing.junit5.webserver.DirectClient; +import io.helidon.nima.testing.junit5.webserver.RoutingTest; +import io.helidon.nima.testing.junit5.webserver.SetUpRoute; +import io.helidon.nima.webclient.http1.Http1Client; +import io.helidon.nima.webclient.http1.Http1ClientResponse; +import io.helidon.nima.webserver.http.ErrorHandler; +import io.helidon.nima.webserver.http.Filter; +import io.helidon.nima.webserver.http.FilterChain; +import io.helidon.nima.webserver.http.HttpRouting; +import io.helidon.nima.webserver.http.RoutingRequest; +import io.helidon.nima.webserver.http.RoutingResponse; +import io.helidon.nima.webserver.http.ServerRequest; +import io.helidon.nima.webserver.http.ServerResponse; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.http.junit5.HttpHeaderMatcher.hasHeader; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@RoutingTest +class ErrorHandlingTest { + private static final Http.HeaderName CONTROL_HEADER = Http.Header.create("X-HELIDON-JUNIT"); + private static final Http.HeaderValue FIRST = Http.Header.create(CONTROL_HEADER, "first"); + private static final Http.HeaderValue SECOND = Http.Header.create(CONTROL_HEADER, "second"); + private static final Http.HeaderValue ROUTING = Http.Header.create(CONTROL_HEADER, "routing"); + private static final Http.HeaderValue CUSTOM = Http.Header.create(CONTROL_HEADER, "custom"); + + private final Http1Client client; + + ErrorHandlingTest(DirectClient client) { + this.client = client; + } + + @SetUpRoute + static void routing(HttpRouting.Builder builder) { + builder.error(FirstException.class, new FirstHandler()) + .error(SecondException.class, new SecondHandler()) + .error(CustomRoutingException.class, new CustomRoutingHandler()) + .addFilter(new FirstFilter()) + .addFilter(new SecondFilter()) + .get("/", ErrorHandlingTest::handler); + } + + @Test + void testOk() { + String response = client.get() + .request(String.class); + assertThat(response, is("Done")); + } + + @Test + void testFirst() { + String response = client.get() + .header(FIRST) + .request(String.class); + assertThat(response, is("First")); + } + + @Test + void testSecond() { + String response = client.get() + .header(SECOND) + .request(String.class); + assertThat(response, is("Second")); + } + + @Test + void testCustom() { + String response = client.get() + .header(CUSTOM) + .request(String.class); + assertThat(response, is("Custom")); + } + + @Test + void testUnhandled() { + try (Http1ClientResponse response = client.get() + .header(ROUTING) + .request()) { + assertThat(response.status(), is(Http.Status.INTERNAL_SERVER_ERROR_500)); + assertThat(response.headers(), hasHeader(Http.HeaderValues.CONTENT_LENGTH_ZERO)); + } + } + + private static void handler(ServerRequest req, ServerResponse res) throws Exception { + if (req.headers().contains(ROUTING)) { + throw new RoutingException(); + } + if (req.headers().contains(CUSTOM)) { + throw new CustomRoutingException(); + } + res.send("Done"); + } + + private static class FirstFilter implements Filter { + @Override + public void filter(FilterChain chain, RoutingRequest req, RoutingResponse res) { + if (req.headers().contains(FIRST)) { + throw new FirstException(); + } + chain.proceed(); + } + } + + private static class SecondFilter implements Filter { + @Override + public void filter(FilterChain chain, RoutingRequest req, RoutingResponse res) { + if (req.headers().contains(SECOND)) { + throw new SecondException(); + } + chain.proceed(); + } + } + + private static class FirstHandler implements ErrorHandler { + @Override + public void handle(ServerRequest req, ServerResponse res, FirstException throwable) { + res.send("First"); + } + } + + private static class SecondHandler implements ErrorHandler { + @Override + public void handle(ServerRequest req, ServerResponse res, SecondException throwable) { + res.send("Second"); + } + } + + private static class CustomRoutingHandler implements ErrorHandler { + @Override + public void handle(ServerRequest req, ServerResponse res, CustomRoutingException throwable) { + res.send("Custom"); + } + } + + private static class FirstException extends RuntimeException { + } + + private static class SecondException extends RuntimeException { + } + + private static class RoutingException extends Exception { + + } + + private static class CustomRoutingException extends RoutingException { + + } +} diff --git a/nima/webserver/webserver/pom.xml b/nima/webserver/webserver/pom.xml index 3f9d3a64fa5..b4074a54b4b 100644 --- a/nima/webserver/webserver/pom.xml +++ b/nima/webserver/webserver/pom.xml @@ -65,10 +65,25 @@ junit-jupiter-api test + + junit-jupiter-params + org.junit.jupiter + test + + + mockito-core + org.mockito + test + org.hamcrest hamcrest-all test + + helidon-common-testing-junit5 + io.helidon.common.testing + test + diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/Executable.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/ErrorHandler.java similarity index 55% rename from nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/Executable.java rename to nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/ErrorHandler.java index 6ea5dd844a1..78f44b123ff 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/Executable.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/ErrorHandler.java @@ -17,15 +17,20 @@ package io.helidon.nima.webserver.http; /** - * A runnable that can throw a checked exception. - * This is to allow users to throw exception from their routes (and these will either end in an - * {@link io.helidon.common.http.InternalServerException}, or will be handled by exception handler. + * The routing error handler. + * Can be mapped to the error cause in {@link io.helidon.nima.webserver.http.HttpRouting}. + * + * @param type of throwable handled by this handler + * @see io.helidon.nima.webserver.http.HttpRouting.Builder#error(Class, ErrorHandler) */ -interface Executable { +@FunctionalInterface +public interface ErrorHandler { /** - * Execute with a possible checked exception. + * Error handling consumer. * - * @throws Exception any exception + * @param req the server request + * @param res the server response + * @param throwable the cause of the error */ - void execute() throws Exception; + void handle(ServerRequest req, ServerResponse res, T throwable); } diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/ErrorHandlers.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/ErrorHandlers.java index 3f472d0447d..b6151e514af 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/ErrorHandlers.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/ErrorHandlers.java @@ -18,6 +18,10 @@ import java.io.UncheckedIOException; import java.net.SocketException; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Callable; import io.helidon.common.http.BadRequestException; import io.helidon.common.http.DirectHandler; @@ -32,8 +36,25 @@ */ public final class ErrorHandlers { private static final System.Logger LOGGER = System.getLogger(ErrorHandlers.class.getName()); + private final IdentityHashMap, ErrorHandler> errorHandlers; - ErrorHandlers() { + private ErrorHandlers(IdentityHashMap, ErrorHandler> errorHandlers) { + this.errorHandlers = errorHandlers; + } + + /** + * Create error handlers. + * + * @param errorHandlers map of type to error handler + * @return new error handlers + */ + public static ErrorHandlers create(Map, ErrorHandler> errorHandlers) { + return new ErrorHandlers(new IdentityHashMap<>(errorHandlers)); + } + + @Override + public String toString() { + return "ErrorHandlers for " + errorHandlers.keySet(); } /** @@ -45,9 +66,9 @@ public final class ErrorHandlers { * @param response HTTP server response * @param task task to execute */ - public void runWithErrorHandling(ConnectionContext ctx, ServerRequest request, ServerResponse response, Executable task) { + public void runWithErrorHandling(ConnectionContext ctx, ServerRequest request, ServerResponse response, Callable task) { try { - task.execute(); + task.call(); } catch (CloseConnectionException | UncheckedIOException e) { // these errors must "bubble up" throw e; @@ -65,10 +86,26 @@ public void runWithErrorHandling(ConnectionContext ctx, ServerRequest request, S } catch (InternalServerException e) { // this is the place error handling must be done // check if error handler exists for cause - if so, use it - if (hasErrorHandler(e.getCause())) { - handleError(ctx, request, response, e.getCause()); + ErrorHandler errorHandler = null; + Throwable exception = null; + + if (e.getCause() != null) { + var maybeEh = errorHandler(e.getCause().getClass()); + if (maybeEh.isPresent()) { + errorHandler = maybeEh.get(); + exception = e.getCause(); + } + } + + if (errorHandler == null) { + errorHandler = errorHandler(e.getClass()).orElse(null); + exception = e; + } + + if (errorHandler == null) { + unhandledError(ctx, request, response, exception); } else { - handleError(ctx, request, response, e); + handleError(ctx, request, response, exception, errorHandler); } } catch (HttpException e) { handleError(ctx, request, response, e); @@ -82,6 +119,26 @@ public void runWithErrorHandling(ConnectionContext ctx, ServerRequest request, S } } + @SuppressWarnings("unchecked") + Optional> errorHandler(Class exceptionClass) { + // then look for error handlers that handle supertypes of this exception from lower to higher + Class throwableClass = exceptionClass; + while (true) { + // first look for exact match + ErrorHandler errorHandler = errorHandlers.get(throwableClass); + if (errorHandler != null) { + return Optional.of((ErrorHandler) errorHandler); + } + if (!Throwable.class.isAssignableFrom(throwableClass)) { + return Optional.empty(); + } + if (throwableClass == Throwable.class) { + return Optional.empty(); + } + throwableClass = (Class) throwableClass.getSuperclass(); + } + } + private void handleRequestException(ConnectionContext ctx, ServerRequest request, ServerResponse response, @@ -102,12 +159,13 @@ private void handleRequestException(ConnectionContext ctx, ctx.directHandlers().handle(e, response, keepAlive); } - private boolean hasErrorHandler(Throwable cause) { - // TODO needs implementation (separate issue) - return true; + private void handleError(ConnectionContext ctx, ServerRequest request, ServerResponse response, Throwable e) { + errorHandler(e.getClass()) + .ifPresentOrElse(it -> handleError(ctx, request, response, e, (ErrorHandler) it), + () -> unhandledError(ctx, request, response, e)); } - private void handleError(ConnectionContext ctx, ServerRequest request, ServerResponse response, Throwable e) { + private void unhandledError(ConnectionContext ctx, ServerRequest request, ServerResponse response, Throwable e) { // to be handled by error handler handleRequestException(ctx, request, response, RequestException.builder() .cause(e) @@ -128,4 +186,17 @@ private void handleError(ConnectionContext ctx, ServerRequest request, ServerRes .request(DirectTransportRequest.create(request.prologue(), request.headers())) .build()); } + + private void handleError(ConnectionContext ctx, + ServerRequest request, + ServerResponse response, + Throwable e, + ErrorHandler it) { + try { + it.handle(request, response, e); + } catch (Exception ex) { + ctx.log(LOGGER, System.Logger.Level.TRACE, "Failed to handle exception.", ex); + unhandledError(ctx, request, response, e); + } + } } diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/Filters.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/Filters.java index 56a026047d7..686e5522297 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/Filters.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/Filters.java @@ -18,6 +18,7 @@ import java.util.Iterator; import java.util.List; +import java.util.concurrent.Callable; import io.helidon.common.http.Http; import io.helidon.common.http.HttpException; @@ -44,7 +45,7 @@ private Filters(ErrorHandlers errorHandlers, List filters) { /** * Create filters. * - * @param errorHandlers + * @param errorHandlers error handlers to handle thrown exceptions * @param filters list of filters to use * @return filters */ @@ -71,7 +72,7 @@ public void afterStop() { * @param routingExecutor this handler is called after all filters finish processing * (unless a filter does not invoke the chain) */ - public void filter(ConnectionContext ctx, RoutingRequest request, RoutingResponse response, Executable routingExecutor) { + public void filter(ConnectionContext ctx, RoutingRequest request, RoutingResponse response, Callable routingExecutor) { if (noFilters) { errorHandlers.runWithErrorHandling(ctx, request, response, routingExecutor); return; @@ -86,16 +87,16 @@ private static final class FilterChainImpl implements FilterChain { private final ConnectionContext ctx; private final ErrorHandlers errorHandlers; private final Iterator filters; - private final Executable routingExecutor; - private RoutingRequest request; - private RoutingResponse response; + private final Callable routingExecutor; + private final RoutingRequest request; + private final RoutingResponse response; private FilterChainImpl(ConnectionContext ctx, ErrorHandlers errorHandlers, List filters, RoutingRequest request, RoutingResponse response, - Executable routingExecutor) { + Callable routingExecutor) { this.ctx = ctx; this.errorHandlers = errorHandlers; this.filters = filters.iterator(); @@ -122,8 +123,9 @@ public void proceed() { } } - private void runNextFilter() { + private Void runNextFilter() { filters.next().filter(this, request, response); + return null; } } diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java index ef25ad68f65..f0f8cf38087 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java @@ -17,7 +17,10 @@ package io.helidon.nima.webserver.http; import java.util.ArrayList; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -42,14 +45,15 @@ public final class HttpRouting implements Routing { private final Filters filters; private final ServiceRoute rootRoute; - // todo configure on HTTP routing - private final ErrorHandlers errorHandlers = new ErrorHandlers(); + private final ErrorHandlers errorHandlers; private final List features; private HttpRouting(Builder builder) { + this.errorHandlers = ErrorHandlers.create(builder.errorHandlers); this.filters = Filters.create(errorHandlers, List.copyOf(builder.filters)); this.rootRoute = builder.rootRules.build(); this.features = List.copyOf(builder.features); + } /** @@ -125,6 +129,7 @@ public static class Builder implements HttpRules, io.helidon.common.Builder filters = new ArrayList<>(); private final ServiceRules rootRules = new ServiceRules(); private final List features = new ArrayList<>(); + private final Map, ErrorHandler> errorHandlers = new IdentityHashMap<>(); private Builder() { } @@ -158,6 +163,19 @@ public Builder addFeature(Supplier feature) { return this; } + /** + * Registers an error handler that handles the given type of exceptions. + * + * @param exceptionClass the type of exception to handle by this handler + * @param handler the error handler + * @param exception type + * @return updated builder + */ + public Builder error(Class exceptionClass, ErrorHandler handler) { + this.errorHandlers.put(exceptionClass, handler); + return this; + } + @Override public Builder register(Supplier... service) { rootRules.register(service); @@ -303,7 +321,7 @@ public Builder any(String pattern, Handler handler) { } } - private static final class RoutingExecutor implements Executable { + private static final class RoutingExecutor implements Callable { private final ConnectionContext ctx; private final RoutingRequest request; private final RoutingResponse response; @@ -320,12 +338,12 @@ private RoutingExecutor(ConnectionContext ctx, } @Override - public void execute() throws Exception { + public Void call() throws Exception { // initial attempt - most common case, handled separately RoutingResult result = doRoute(ctx, request, response); if (result == RoutingResult.FINISH) { - return; + return null; } if (result == RoutingResult.NONE) { throw new NotFoundException("Endpoint not found"); @@ -346,7 +364,7 @@ public void execute() throws Exception { // finished and done if (result == RoutingResult.FINISH) { - return; + return null; } throw new NotFoundException("Endpoint not found"); } diff --git a/nima/webserver/webserver/src/test/java/io/helidon/nima/webserver/http/ErrorHandlersTest.java b/nima/webserver/webserver/src/test/java/io/helidon/nima/webserver/http/ErrorHandlersTest.java new file mode 100644 index 00000000000..d0b72a95b67 --- /dev/null +++ b/nima/webserver/webserver/src/test/java/io/helidon/nima/webserver/http/ErrorHandlersTest.java @@ -0,0 +1,210 @@ +/* + * 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.nima.webserver.http; + +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +import io.helidon.common.http.Http; +import io.helidon.common.http.HttpPrologue; +import io.helidon.common.uri.UriFragment; +import io.helidon.common.uri.UriPath; +import io.helidon.common.uri.UriQuery; +import io.helidon.nima.http.media.ReadableEntityBase; +import io.helidon.nima.webserver.ConnectionContext; + +import org.hamcrest.Matcher; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.ArgumentCaptor; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class ErrorHandlersTest { + static Stream testData() { + return Stream.of( + new TestData(ErrorHandlers.create(Map.of()), + optionalEmpty(), + optionalEmpty(), + optionalEmpty(), + optionalEmpty(), + optionalEmpty(), + optionalEmpty()), + new TestData(ErrorHandlers.create(Map.of(Throwable.class, new TestHandler<>("Throwable"))), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class))), + new TestData(ErrorHandlers.create(Map.of(Exception.class, new TestHandler<>("Exception"))), + optionalEmpty(), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class))), + new TestData(ErrorHandlers.create(Map.of(RuntimeException.class, new TestHandler<>("RuntimeException"))), + optionalEmpty(), + optionalEmpty(), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalEmpty()), + new TestData(ErrorHandlers.create(Map.of(TopRuntimeException.class, new TestHandler<>("TopRuntimeException"))), + optionalEmpty(), + optionalEmpty(), + optionalEmpty(), + optionalValue(instanceOf(TestHandler.class)), + optionalValue(instanceOf(TestHandler.class)), + optionalEmpty()), + new TestData(ErrorHandlers.create(Map.of(ChildRuntimeException.class, + new TestHandler<>("ChildRuntimeException"))), + optionalEmpty(), + optionalEmpty(), + optionalEmpty(), + optionalEmpty(), + optionalValue(instanceOf(TestHandler.class)), + optionalEmpty()) + ); + } + + @ParameterizedTest + @MethodSource("testData") + void testHandleFound(TestData testData) { + ErrorHandlers handlers = testData.handlers(); + + assertAll( + () -> assertThat(handlers.errorHandler(Throwable.class), testData.tMatcher()), + () -> assertThat(handlers.errorHandler(Exception.class), testData.eMatcher()), + () -> assertThat(handlers.errorHandler(RuntimeException.class), testData.rtMatcher()), + () -> assertThat(handlers.errorHandler(TopRuntimeException.class), testData.trtMatcher()), + () -> assertThat(handlers.errorHandler(ChildRuntimeException.class), testData.crtMatcher()), + () -> assertThat(handlers.errorHandler(OtherException.class), testData.oMatcher()) + ); + } + + @Test + void testHandler() { + ErrorHandlers handlers = ErrorHandlers.create(Map.of(TopRuntimeException.class, + (req, res, t) -> res.send(t.getMessage()))); + + testHandler(handlers, new TopRuntimeException(), "Top"); + testHandler(handlers, new ChildRuntimeException(), "Child"); + testNoHandler(handlers, new OtherException(), "Other"); + } + + private void testNoHandler(ErrorHandlers handlers, Exception e, String message) { + ServerRequest req = mock(ServerRequest.class); + ServerResponse res = mock(ServerResponse.class); + ConnectionContext ctx = mock(ConnectionContext.class); + + when(req.prologue()).thenReturn(HttpPrologue.create("http", + "1.0", + Http.Method.GET, + UriPath.create("/"), + UriQuery.empty(), + UriFragment.empty())); + when(req.content()).thenReturn(ReadableEntityBase.empty()); + when(ctx.directHandlers()).thenReturn(DirectHandlers.builder().build()); + + handlers.runWithErrorHandling(ctx, req, res, () -> { + throw e; + }); + + var status = ArgumentCaptor.forClass(Http.Status.class); + verify(res).status(status.capture()); + assertThat(status.getValue(), is(Http.Status.INTERNAL_SERVER_ERROR_500)); + + var sent = ArgumentCaptor.forClass(byte[].class); + verify(res).send(sent.capture()); + assertThat(sent.getValue(), is("Other".getBytes(StandardCharsets.UTF_8))); + } + + private void testHandler(ErrorHandlers handlers, Exception e, String message) { + ServerRequest req = mock(ServerRequest.class); + ServerResponse res = mock(ServerResponse.class); + ConnectionContext ctx = mock(ConnectionContext.class); + + handlers.runWithErrorHandling(ctx, req, res, () -> { + throw e; + }); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(res).send(captor.capture()); + assertThat(captor.getValue(), is(message)); + } + + private static class TopRuntimeException extends RuntimeException { + private TopRuntimeException() { + this("Top"); + } + + public TopRuntimeException(String message) { + super(message); + } + } + + private static class ChildRuntimeException extends TopRuntimeException { + private ChildRuntimeException() { + super("Child"); + } + } + + private static class OtherException extends Exception { + public OtherException() { + super("Other"); + } + } + + private record TestData(ErrorHandlers handlers, + Matcher>> tMatcher, + Matcher>> eMatcher, + Matcher>> rtMatcher, + Matcher>> trtMatcher, + Matcher>> crtMatcher, + Matcher>> oMatcher) { + } + + private static class TestHandler implements ErrorHandler { + private final String message; + + TestHandler(String message) { + this.message = message; + } + + @Override + public void handle(ServerRequest req, ServerResponse res, T throwable) { + } + + @Override + public String toString() { + return message; + } + } +} \ No newline at end of file From 8256e47da527b439ebd2b7831d73436c2a11a267 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Mon, 21 Nov 2022 10:27:55 -0500 Subject: [PATCH 10/36] move bean utils from builder spi to processor module. (#5448) --- pico/builder/builder/pom.xml | 19 --- .../pico/builder/spi/package-info.java | 2 +- .../builder/src/main/java/module-info.java | 2 +- .../pico/builder/spi/BeanUtilsTest.java | 148 ------------------ pico/builder/processor-tools/pom.xml | 15 ++ .../builder/processor/tools}/BeanUtils.java | 2 +- .../builder/processor/tools/BodyContext.java | 1 - .../tools/DefaultBuilderCreator.java | 1 - .../processor/tools/BeanUtilsTest.java | 148 ++++++++++++++++++ 9 files changed, 166 insertions(+), 172 deletions(-) delete mode 100644 pico/builder/builder/src/test/java/io/helidon/pico/builder/spi/BeanUtilsTest.java rename pico/builder/{builder/src/main/java/io/helidon/pico/builder/spi => processor-tools/src/main/java/io/helidon/pico/builder/processor/tools}/BeanUtils.java (99%) create mode 100644 pico/builder/processor-tools/src/test/java/io/helidon/pico/builder/processor/tools/BeanUtilsTest.java diff --git a/pico/builder/builder/pom.xml b/pico/builder/builder/pom.xml index d6d6a439791..e53b29f5852 100644 --- a/pico/builder/builder/pom.xml +++ b/pico/builder/builder/pom.xml @@ -38,25 +38,6 @@ helidon-config-metadata provided - - io.helidon.common - helidon-common - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/package-info.java b/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/package-info.java index 3a07daa7b0d..54451dc3e75 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/package-info.java +++ b/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/package-info.java @@ -15,6 +15,6 @@ */ /** - * Builder runtime tooling spi utilities and helpers. + * Builder runtime tooling SPI. */ package io.helidon.pico.builder.spi; diff --git a/pico/builder/builder/src/main/java/module-info.java b/pico/builder/builder/src/main/java/module-info.java index 12fd7947aa3..4488f9b61fa 100644 --- a/pico/builder/builder/src/main/java/module-info.java +++ b/pico/builder/builder/src/main/java/module-info.java @@ -15,7 +15,7 @@ */ /** - * The Pico Builder module. + * The Pico Builder API / SPI module. */ module io.helidon.pico.builder { exports io.helidon.pico.builder; diff --git a/pico/builder/builder/src/test/java/io/helidon/pico/builder/spi/BeanUtilsTest.java b/pico/builder/builder/src/test/java/io/helidon/pico/builder/spi/BeanUtilsTest.java deleted file mode 100644 index b0fafca6aa5..00000000000 --- a/pico/builder/builder/src/test/java/io/helidon/pico/builder/spi/BeanUtilsTest.java +++ /dev/null @@ -1,148 +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.pico.builder.spi; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static io.helidon.pico.builder.spi.BeanUtils.isBooleanType; -import static io.helidon.pico.builder.spi.BeanUtils.isValidMethodType; -import static io.helidon.pico.builder.spi.BeanUtils.validateAndParseMethodName; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.core.Is.is; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class BeanUtilsTest { - - @Test - void testIsBooleanType() { - assertThat(isBooleanType(boolean.class), is(true)); - assertThat(isBooleanType(Boolean.class), is(true)); - assertThat(isBooleanType(String.class), is(false)); - assertThat(isBooleanType(""), is(false)); - } - - @Test - void testIsValidMethodType() { - assertThat(isValidMethodType(boolean.class.getName()), is(true)); - assertThat(isValidMethodType(String.class.getName()), is(true)); - assertThat(isValidMethodType(Collection.class.getName()), is(true)); - assertThat(isValidMethodType(Map.class.getName()), is(true)); - assertThat(isValidMethodType(Set.class.getName()), is(true)); - assertThat(isValidMethodType(List.class.getName()), is(true)); - assertThat(isValidMethodType(Object.class.getName()), is(true)); - assertThat(isValidMethodType(""), is(false)); - assertThat(isValidMethodType(void.class.getName()), is(false)); - assertThat(isValidMethodType(Void.class.getName()), is(false)); - } - - @Test - void testValidateAndParseMethodName() { - AtomicReference>> attrName = new AtomicReference<>(); - - RuntimeException e = assertThrows(RuntimeException.class, - () -> validateAndParseMethodName("x", "", true, attrName)); - assertThat(e.getMessage(), is("invalid return type: x")); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("isAlpha", Boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alpha", "isAlpha"))); - - assertThat(validateAndParseMethodName("isAlpha", boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alpha", "isAlpha"))); - - assertThat(validateAndParseMethodName("getAlpha", boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alpha"))); - - assertThat(validateAndParseMethodName("getAlpha", Boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alpha"))); - - assertThat(validateAndParseMethodName("getAlpha", String.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alpha"))); - - assertThat(validateAndParseMethodName("getAlpha", Object.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alpha"))); - - assertThat(validateAndParseMethodName("isAlphaNumeric", boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alphaNumeric", "isAlphaNumeric"))); - - assertThat(validateAndParseMethodName("getAlphaNumeric", boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("alphaNumeric"))); - - assertThat(validateAndParseMethodName("isX", boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("x", "isX"))); - - assertThat(validateAndParseMethodName("getX", boolean.class.getName(), false, attrName), is(true)); - assertThat(attrName.get(), optionalValue(contains("x"))); - - // negative cases ... - assertThat(validateAndParseMethodName("isX", String.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("is_AlphaNumeric", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("is", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("is", Boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("get", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("get", Boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("get1AlphaNumeric", Boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("getalphaNumeric", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("isalphaNumeric", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("is9alphaNumeric", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("isAlphaNumeric", void.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("getAlphaNumeric", Void.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("x", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("IsX", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - - assertThat(validateAndParseMethodName("GetX", boolean.class.getName(), false, attrName), is(false)); - assertThat(attrName.get(), optionalEmpty()); - } - -} diff --git a/pico/builder/processor-tools/pom.xml b/pico/builder/processor-tools/pom.xml index 9996da8611f..eb075bc8242 100644 --- a/pico/builder/processor-tools/pom.xml +++ b/pico/builder/processor-tools/pom.xml @@ -52,6 +52,21 @@ io.helidon.config helidon-config-metadata + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/BeanUtils.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BeanUtils.java similarity index 99% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/BeanUtils.java rename to pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BeanUtils.java index 48348b33204..f8fcb560ea3 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/BeanUtils.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BeanUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.spi; +package io.helidon.pico.builder.processor.tools; import java.util.Collections; import java.util.List; diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java index dfb8946bcfb..5fcc2c02857 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java @@ -26,7 +26,6 @@ import java.util.concurrent.atomic.AtomicReference; import io.helidon.pico.builder.processor.spi.TypeInfo; -import io.helidon.pico.builder.spi.BeanUtils; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; import io.helidon.pico.types.TypeName; diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java index 54beea7e0a3..a8619701068 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java @@ -41,7 +41,6 @@ import io.helidon.pico.builder.processor.spi.DefaultTypeAndBody; import io.helidon.pico.builder.processor.spi.TypeAndBody; import io.helidon.pico.builder.processor.spi.TypeInfo; -import io.helidon.pico.builder.spi.BeanUtils; import io.helidon.pico.builder.spi.RequiredAttributeVisitor; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; diff --git a/pico/builder/processor-tools/src/test/java/io/helidon/pico/builder/processor/tools/BeanUtilsTest.java b/pico/builder/processor-tools/src/test/java/io/helidon/pico/builder/processor/tools/BeanUtilsTest.java new file mode 100644 index 00000000000..e792c8f8c6a --- /dev/null +++ b/pico/builder/processor-tools/src/test/java/io/helidon/pico/builder/processor/tools/BeanUtilsTest.java @@ -0,0 +1,148 @@ +/* + * 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.pico.builder.processor.tools; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import io.helidon.common.testing.junit5.OptionalMatcher; + +import org.hamcrest.Matchers; +import org.hamcrest.core.Is; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static io.helidon.pico.builder.processor.tools.BeanUtils.isBooleanType; +import static io.helidon.pico.builder.processor.tools.BeanUtils.isValidMethodType; +import static io.helidon.pico.builder.processor.tools.BeanUtils.validateAndParseMethodName; +import static org.hamcrest.MatcherAssert.assertThat; + +class BeanUtilsTest { + + @Test + void testIsBooleanType() { + assertThat(isBooleanType(boolean.class), Is.is(true)); + assertThat(isBooleanType(Boolean.class), Is.is(true)); + assertThat(isBooleanType(String.class), Is.is(false)); + assertThat(isBooleanType(""), Is.is(false)); + } + + @Test + void testIsValidMethodType() { + assertThat(isValidMethodType(boolean.class.getName()), Is.is(true)); + assertThat(isValidMethodType(String.class.getName()), Is.is(true)); + assertThat(isValidMethodType(Collection.class.getName()), Is.is(true)); + assertThat(isValidMethodType(Map.class.getName()), Is.is(true)); + assertThat(isValidMethodType(Set.class.getName()), Is.is(true)); + assertThat(isValidMethodType(List.class.getName()), Is.is(true)); + assertThat(isValidMethodType(Object.class.getName()), Is.is(true)); + assertThat(isValidMethodType(""), Is.is(false)); + assertThat(isValidMethodType(void.class.getName()), Is.is(false)); + assertThat(isValidMethodType(Void.class.getName()), Is.is(false)); + } + + @Test + void testValidateAndParseMethodName() { + AtomicReference>> attrName = new AtomicReference<>(); + + RuntimeException e = Assertions.assertThrows(RuntimeException.class, + () -> validateAndParseMethodName("x", "", true, attrName)); + assertThat(e.getMessage(), Is.is("invalid return type: x")); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("isAlpha", Boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alpha", "isAlpha"))); + + assertThat(validateAndParseMethodName("isAlpha", boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alpha", "isAlpha"))); + + assertThat(validateAndParseMethodName("getAlpha", boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alpha"))); + + assertThat(validateAndParseMethodName("getAlpha", Boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alpha"))); + + assertThat(validateAndParseMethodName("getAlpha", String.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alpha"))); + + assertThat(validateAndParseMethodName("getAlpha", Object.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alpha"))); + + assertThat(validateAndParseMethodName("isAlphaNumeric", boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alphaNumeric", "isAlphaNumeric"))); + + assertThat(validateAndParseMethodName("getAlphaNumeric", boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("alphaNumeric"))); + + assertThat(validateAndParseMethodName("isX", boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("x", "isX"))); + + assertThat(validateAndParseMethodName("getX", boolean.class.getName(), false, attrName), Is.is(true)); + assertThat(attrName.get(), OptionalMatcher.optionalValue(Matchers.contains("x"))); + + // negative cases ... + assertThat(validateAndParseMethodName("isX", String.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("is_AlphaNumeric", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("is", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("is", Boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("get", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("get", Boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("get1AlphaNumeric", Boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("getalphaNumeric", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("isalphaNumeric", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("is9alphaNumeric", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("isAlphaNumeric", void.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("getAlphaNumeric", Void.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("x", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("IsX", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + + assertThat(validateAndParseMethodName("GetX", boolean.class.getName(), false, attrName), Is.is(false)); + assertThat(attrName.get(), OptionalMatcher.optionalEmpty()); + } + +} From 453da5924124e22239c9b5a89e4fda28e14c4efc Mon Sep 17 00:00:00 2001 From: Andrii Serkes Date: Mon, 21 Nov 2022 23:37:32 +0100 Subject: [PATCH 11/36] remove -Ddocker.build=true (#5485) * remove -Ddocker.build=true Signed-off-by: aserkes --- .../src/main/archetype/common/files/Dockerfile.jlink.mustache | 2 +- examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink | 4 ++-- examples/integrations/neo4j/neo4j-se/Dockerfile.jlink | 4 ++-- examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink | 2 +- examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink | 2 +- .../helidon-standalone-quickstart-mp/Dockerfile.jlink | 2 +- .../helidon-standalone-quickstart-se/Dockerfile.jlink | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/archetypes/helidon/src/main/archetype/common/files/Dockerfile.jlink.mustache b/archetypes/helidon/src/main/archetype/common/files/Dockerfile.jlink.mustache index e70775fd065..df76d3b74d7 100644 --- a/archetypes/helidon/src/main/archetype/common/files/Dockerfile.jlink.mustache +++ b/archetypes/helidon/src/main/archetype/common/files/Dockerfile.jlink.mustache @@ -13,7 +13,7 @@ RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build to create the custom Java Runtime Image # Incremental docker builds will resume here when you change sources ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN mvn package -Pjlink-image -DskipTests RUN echo "done!" # 2nd stage, build the final image with the JRI built in the 1st stage diff --git a/examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink b/examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink index 946eb4073f6..b011b1ebb35 100644 --- a/examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink +++ b/examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Oracle and/or its affiliates. +# 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. @@ -28,7 +28,7 @@ RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build to create the custom Java Runtime Image # Incremental docker builds will resume here when you change sources ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN mvn package -Pjlink-image -DskipTests RUN echo "done!" # 2nd stage, build the final image with the JRI built in the 1st stage diff --git a/examples/integrations/neo4j/neo4j-se/Dockerfile.jlink b/examples/integrations/neo4j/neo4j-se/Dockerfile.jlink index cad390da664..f0f92e3ac3b 100644 --- a/examples/integrations/neo4j/neo4j-se/Dockerfile.jlink +++ b/examples/integrations/neo4j/neo4j-se/Dockerfile.jlink @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Oracle and/or its affiliates. +# 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. @@ -28,7 +28,7 @@ RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build to create the custom Java Runtime Image # Incremental docker builds will resume here when you change sources ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN mvn package -Pjlink-image -DskipTests RUN echo "done!" # 2nd stage, build the final image with the JRI built in the 1st stage diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink index 4648aed01dd..1f0bc842fdc 100644 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink +++ b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink @@ -28,7 +28,7 @@ RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build to create the custom Java Runtime Image # Incremental docker builds will resume here when you change sources ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN mvn package -Pjlink-image -DskipTests RUN echo "done!" # 2nd stage, build the final image with the JRI built in the 1st stage diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink b/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink index ffbea87cbd1..3578beaf34a 100644 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink +++ b/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink @@ -28,7 +28,7 @@ RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build to create the custom Java Runtime Image # Incremental docker builds will resume here when you change sources ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN mvn package -Pjlink-image -DskipTests RUN echo "done!" # 2nd stage, build the final image with the JRI built in the 1st stage diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink index 4648aed01dd..1f0bc842fdc 100644 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink +++ b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink @@ -28,7 +28,7 @@ RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build to create the custom Java Runtime Image # Incremental docker builds will resume here when you change sources ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN mvn package -Pjlink-image -DskipTests RUN echo "done!" # 2nd stage, build the final image with the JRI built in the 1st stage diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink index ffbea87cbd1..3578beaf34a 100644 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink +++ b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink @@ -28,7 +28,7 @@ RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build to create the custom Java Runtime Image # Incremental docker builds will resume here when you change sources ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN mvn package -Pjlink-image -DskipTests RUN echo "done!" # 2nd stage, build the final image with the JRI built in the 1st stage From f5f6d243b0c2a407a147774e468ea2ae63c2c489 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 22 Nov 2022 19:44:43 +0300 Subject: [PATCH 12/36] Fix Guava version to match that required by the grpc-java libraries (#5504) --- dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pom.xml b/dependencies/pom.xml index d0fe5575a9e..ec5a4b09012 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -57,7 +57,7 @@ 17.1 2.9.0 1.49.2 - 30.0-jre + 31.1-jre 2.1.212 1.3 6.1.4.Final From 10038f157eedfd3973dce5bc4a8ea106c480c0c0 Mon Sep 17 00:00:00 2001 From: Andrii Serkes Date: Thu, 24 Nov 2022 07:53:40 +0100 Subject: [PATCH 13/36] 5379 TempDir support for tests (#5508) tempDir support for tests Signed-off-by: aserkes --- .../testing/junit5/TemporaryFolderExt.java | 1 + .../config/ConfigSourceMetaConfigTest.java | 13 ++-- .../config/DirectoryConfigSourceTest.java | 18 +++--- .../helidon/config/FileConfigSourceTest.java | 6 -- .../config/FileOverrideSourceTest.java | 5 -- .../helidon/config/FileSourceHelperTest.java | 17 +++--- .../git/GitConfigSourceBuilderTest.java | 59 +++++++------------ .../multipart/FileServiceTest.java | 6 +- .../FileSystemContentHandlerTest.java | 19 +++--- .../testsupport/TemporaryFolder.java | 1 + .../testsupport/TemporaryFolderExtension.java | 1 + 11 files changed, 55 insertions(+), 91 deletions(-) diff --git a/common/testing/junit5/src/main/java/io/helidon/common/testing/junit5/TemporaryFolderExt.java b/common/testing/junit5/src/main/java/io/helidon/common/testing/junit5/TemporaryFolderExt.java index e5febeae1fb..b2bdbc44f8d 100644 --- a/common/testing/junit5/src/main/java/io/helidon/common/testing/junit5/TemporaryFolderExt.java +++ b/common/testing/junit5/src/main/java/io/helidon/common/testing/junit5/TemporaryFolderExt.java @@ -46,6 +46,7 @@ * the test class have finished. * */ +@Deprecated public class TemporaryFolderExt implements BeforeEachCallback, AfterEachCallback { private Path root; diff --git a/config/config/src/test/java/io/helidon/config/ConfigSourceMetaConfigTest.java b/config/config/src/test/java/io/helidon/config/ConfigSourceMetaConfigTest.java index cd12819cd64..6274ddcd39c 100644 --- a/config/config/src/test/java/io/helidon/config/ConfigSourceMetaConfigTest.java +++ b/config/config/src/test/java/io/helidon/config/ConfigSourceMetaConfigTest.java @@ -23,7 +23,6 @@ import java.util.List; import io.helidon.common.testing.junit5.RestoreSystemPropertiesExt; -import io.helidon.common.testing.junit5.TemporaryFolderExt; import io.helidon.config.spi.ConfigNode.ObjectNode; import io.helidon.config.spi.ConfigSource; @@ -31,7 +30,7 @@ import org.glassfish.grizzly.http.util.HttpStatus; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; import static com.xebialabs.restito.builder.stub.StubHttp.whenHttp; import static com.xebialabs.restito.semantics.Action.status; @@ -53,9 +52,6 @@ public class ConfigSourceMetaConfigTest { private static final String TEST_ENV_VAR_VALUE = "This Is My ENV VARS Value."; private static final String RELATIVE_PATH_TO_RESOURCE = "/src/test/resources/"; - @RegisterExtension - public TemporaryFolderExt folder = TemporaryFolderExt.build(); - @Test @ExtendWith(RestoreSystemPropertiesExt.class) public void testSystemProperties() { @@ -65,9 +61,9 @@ public void testSystemProperties() { ObjectNode.builder() .addValue("type", "system-properties") .build())); - + ConfigSource source = singleSource(metaConfig); - + assertThat(source, is(instanceOf(AbstractConfigSource.class))); Config config = justFrom(source); @@ -132,8 +128,7 @@ public void testFile() { } @Test - public void testDirectory() throws IOException { - File folder = this.folder.newFolder(); + public void testDirectory(@TempDir File folder) throws IOException { Files.write(Files.createFile(new File(folder, "username").toPath()), "libor".getBytes()); Files.write(Files.createFile(new File(folder, "password").toPath()), "^ery$ecretP&ssword".getBytes()); diff --git a/config/config/src/test/java/io/helidon/config/DirectoryConfigSourceTest.java b/config/config/src/test/java/io/helidon/config/DirectoryConfigSourceTest.java index ddebdd2f938..5868a5411f3 100644 --- a/config/config/src/test/java/io/helidon/config/DirectoryConfigSourceTest.java +++ b/config/config/src/test/java/io/helidon/config/DirectoryConfigSourceTest.java @@ -22,13 +22,12 @@ import java.time.Instant; import java.util.Optional; -import io.helidon.common.testing.junit5.TemporaryFolderExt; import io.helidon.config.spi.ConfigContent; import io.helidon.config.spi.ConfigNode.ObjectNode; import io.helidon.config.spi.ConfigSource; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; import static io.helidon.config.ValueNodeMatcher.valueNode; import static org.hamcrest.CoreMatchers.not; @@ -44,9 +43,9 @@ */ public class DirectoryConfigSourceTest { - @RegisterExtension - static TemporaryFolderExt folder = TemporaryFolderExt.build(); - + @TempDir + File tempFolder; + @Test public void testDescriptionMandatory() { ConfigSource configSource = ConfigSources.directory("secrets").build(); @@ -71,7 +70,7 @@ public void testLoadNoDirectory() { @Test public void testLoadEmptyDirectory() throws IOException { - DirectoryConfigSource configSource = ConfigSources.directory(folder.newFolder().getAbsolutePath()) + DirectoryConfigSource configSource = ConfigSources.directory(tempFolder.getAbsolutePath()) .build(); Optional maybeContent = configSource.load(); @@ -93,11 +92,10 @@ public void testLoadEmptyDirectory() throws IOException { @Test public void testLoadDirectory() throws IOException { - File folder = DirectoryConfigSourceTest.folder.newFolder(); - Files.write(Files.createFile(new File(folder, "username").toPath()), "libor".getBytes()); - Files.write(Files.createFile(new File(folder, "password").toPath()), "^ery$ecretP&ssword".getBytes()); + Files.write(Files.createFile(new File(tempFolder, "username").toPath()), "libor".getBytes()); + Files.write(Files.createFile(new File(tempFolder, "password").toPath()), "^ery$ecretP&ssword".getBytes()); - DirectoryConfigSource configSource = ConfigSources.directory(folder.getAbsolutePath()) + DirectoryConfigSource configSource = ConfigSources.directory(tempFolder.getAbsolutePath()) .build(); Optional maybeContent = configSource.load(); diff --git a/config/config/src/test/java/io/helidon/config/FileConfigSourceTest.java b/config/config/src/test/java/io/helidon/config/FileConfigSourceTest.java index c03d865ab19..23761ea50fe 100644 --- a/config/config/src/test/java/io/helidon/config/FileConfigSourceTest.java +++ b/config/config/src/test/java/io/helidon/config/FileConfigSourceTest.java @@ -25,12 +25,10 @@ import io.helidon.common.media.type.MediaType; import io.helidon.common.media.type.MediaTypes; -import io.helidon.common.testing.junit5.TemporaryFolderExt; import io.helidon.config.spi.ConfigParser; import io.helidon.config.spi.ConfigSource; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; import static org.hamcrest.CoreMatchers.not; @@ -48,10 +46,6 @@ public class FileConfigSourceTest { private static final MediaType TEST_MEDIA_TYPE = MediaTypes.create("my/media/type"); private static final String RELATIVE_PATH_TO_RESOURCE = "/src/test/resources/"; - @RegisterExtension - static TemporaryFolderExt folder = TemporaryFolderExt.build(); - - @Test public void testDescriptionMandatory() { ConfigSource configSource = ConfigSources.file("application.conf").build(); diff --git a/config/config/src/test/java/io/helidon/config/FileOverrideSourceTest.java b/config/config/src/test/java/io/helidon/config/FileOverrideSourceTest.java index 69ebc3965b8..6c475cc2900 100644 --- a/config/config/src/test/java/io/helidon/config/FileOverrideSourceTest.java +++ b/config/config/src/test/java/io/helidon/config/FileOverrideSourceTest.java @@ -19,12 +19,10 @@ import java.nio.file.Paths; import java.util.Optional; -import io.helidon.common.testing.junit5.TemporaryFolderExt; import io.helidon.config.spi.ConfigContent; import io.helidon.config.spi.OverrideSource; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; @@ -37,9 +35,6 @@ public class FileOverrideSourceTest { private static final String RELATIVE_PATH_TO_RESOURCE = "/src/test/resources/"; - @RegisterExtension - static TemporaryFolderExt folder = TemporaryFolderExt.build(); - private static String getDir() { return Paths.get("").toAbsolutePath() + RELATIVE_PATH_TO_RESOURCE; } diff --git a/config/config/src/test/java/io/helidon/config/FileSourceHelperTest.java b/config/config/src/test/java/io/helidon/config/FileSourceHelperTest.java index 71b0913cafa..522bca46188 100644 --- a/config/config/src/test/java/io/helidon/config/FileSourceHelperTest.java +++ b/config/config/src/test/java/io/helidon/config/FileSourceHelperTest.java @@ -18,11 +18,10 @@ import java.io.File; import java.nio.file.Files; - -import io.helidon.common.testing.junit5.TemporaryFolderExt; +import java.nio.file.Path; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; @@ -33,13 +32,13 @@ */ public class FileSourceHelperTest { - @RegisterExtension - static TemporaryFolderExt folder = TemporaryFolderExt.build(); + @TempDir + Path tempFolder; @Test public void testDigestSameContent() throws Exception { - File file1 = folder.newFile("test1"); - File file2 = folder.newFile("test2"); + File file1 = Files.createFile(tempFolder.resolve("test1")).toFile(); + File file2 = Files.createFile(tempFolder.resolve("test2")).toFile(); Files.write(file1.toPath(), "test file".getBytes()); Files.write(file2.toPath(), "test file".getBytes()); @@ -48,8 +47,8 @@ public void testDigestSameContent() throws Exception { @Test public void testDigestDifferentContent() throws Exception { - File file1 = folder.newFile("test1"); - File file2 = folder.newFile("test2"); + File file1 = Files.createFile(tempFolder.resolve("test1")).toFile(); + File file2 = Files.createFile(tempFolder.resolve("test2")).toFile(); Files.write(file1.toPath(), "test file1".getBytes()); Files.write(file2.toPath(), "test file2".getBytes()); diff --git a/config/git/src/test/java/io/helidon/config/git/GitConfigSourceBuilderTest.java b/config/git/src/test/java/io/helidon/config/git/GitConfigSourceBuilderTest.java index 6047d116109..0e1e7bdd6f0 100644 --- a/config/git/src/test/java/io/helidon/config/git/GitConfigSourceBuilderTest.java +++ b/config/git/src/test/java/io/helidon/config/git/GitConfigSourceBuilderTest.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Optional; -import io.helidon.common.testing.junit5.TemporaryFolderExt; import io.helidon.config.Config; import io.helidon.config.ConfigException; import io.helidon.config.ConfigParsers; @@ -40,7 +39,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; import static io.helidon.config.PollingStrategies.regular; import static io.helidon.config.testing.ValueNodeMatcher.valueNode; @@ -56,9 +55,8 @@ public class GitConfigSourceBuilderTest extends RepositoryTestCase { private Git git; - - @RegisterExtension - static TemporaryFolderExt folder = TemporaryFolderExt.build(); + @TempDir + File tempDir; @BeforeEach public void setUp(TestInfo testInfo) throws Exception { @@ -120,8 +118,6 @@ public void testBranch() throws Exception { @Test public void testDirectory() throws IOException, GitAPIException, InterruptedException, Exception { - File tempDir = folder.newFolder(); - try (Git clone = Git.cloneRepository() .setURI(fileUri()) .setDirectory(tempDir) @@ -141,32 +137,29 @@ public void testDirectory() throws IOException, GitAPIException, InterruptedExce @Test public void testDirectoryEmpty() throws IOException, Exception { - Path tempDir = folder.newFolder().toPath(); - try (GitConfigSource source = GitConfigSource .builder() .path("application.properties") .uri(URI.create(fileUri())) - .directory(tempDir) + .directory(tempDir.toPath()) .parser(ConfigParsers.properties()) .build()) { source.init(null); - assertThat(tempDir.resolve("application.properties").toFile().exists(), is(true)); + assertThat(tempDir.toPath().resolve("application.properties").toFile().exists(), is(true)); } } @Test public void testDirNotEmpty() throws IOException { - Path tempDir = folder.newFolder().toPath(); final ConfigException ce = assertThrows(ConfigException.class, () -> { - tempDir.resolve("dust").toFile().createNewFile(); + tempDir.toPath().resolve("dust").toFile().createNewFile(); GitConfigSource .builder() .path("application.properties") .uri(URI.create(fileUri())) - .directory(tempDir) + .directory(tempDir.toPath()) .parser(ConfigParsers.properties()) .build() .init(null); @@ -212,48 +205,42 @@ public void testPolling() throws InterruptedException, IOException, Exception { @Test public void testDescriptionWithDirAndUri() throws IOException, GitAPIException, Exception { - Path dir = folder.newFolder().toPath(); - try (Git clone = Git.cloneRepository() .setURI(fileUri()) - .setDirectory(dir.toFile()) + .setDirectory(tempDir) .call(); GitConfigSource source = GitConfigSource.builder() .path("application.conf") .uri(URI.create(fileUri())) - .directory(dir) + .directory(tempDir.toPath()) .build()) { source.init(null); - assertThat(source.description(), is(String.format("GitConfig[%s|%s#application.conf]", dir, fileUri()))); + assertThat(source.description(), is(String.format("GitConfig[%s|%s#application.conf]", tempDir, fileUri()))); } } @Test public void testDescriptionWithDir() throws IOException, GitAPIException, Exception { - Path dir = folder.newFolder().toPath(); - try (Git clone = Git.cloneRepository() .setURI(fileUri()) - .setDirectory(dir.toFile()) + .setDirectory(tempDir) .call(); GitConfigSource source = GitConfigSource.builder() .path("application.conf") - .directory(dir) + .directory(tempDir.toPath()) .build()) { - assertThat(source.description(), is(String.format("GitConfig[%s#application.conf]", dir))); + assertThat(source.description(), is(String.format("GitConfig[%s#application.conf]", tempDir))); } } @Test public void testDescriptionWithUri() throws IOException, GitAPIException, Exception { - Path dir = folder.newFolder().toPath(); - try (Git clone = Git.cloneRepository() .setURI(fileUri()) - .setDirectory(dir.toFile()) + .setDirectory(tempDir) .call(); GitConfigSource source = GitConfigSource.builder() .path("application.conf") @@ -287,12 +274,10 @@ public void testFromConfigMandatory() { @Test public void testFromConfigAll() throws IOException { - Path directory = folder.newFolder().toPath(); - Config metaConfig = Config.builder(ConfigSources.create(Map.of("path", "application.properties", "uri", fileUri(), "branch", "test", - "directory", directory.toString()))) + "directory", tempDir.toPath().toString()))) .disableSystemPropertiesSource() .disableEnvironmentVariablesSource() .build(); @@ -301,13 +286,11 @@ public void testFromConfigAll() throws IOException { assertThat(builder.target().path(), is("application.properties")); assertThat(builder.target().uri(), is(URI.create(fileUri()))); assertThat(builder.target().branch(), is("test")); - assertThat(builder.target().directory(), is(directory)); + assertThat(builder.target().directory(), is(tempDir.toPath())); } @Test public void testSourceFromConfigByClass() throws Exception { - Path directory = folder.newFolder().toPath(); - Config metaConfig = Config.builder(ConfigSources.create(ObjectNode.builder() .addValue("type", GitConfigSourceProvider.TYPE) @@ -315,7 +298,7 @@ public void testSourceFromConfigByClass() throws Exception { .addValue("path", "application.properties") .addValue("uri", fileUri()) .addValue("branch", "test") - .addValue("directory", directory.toString()) + .addValue("directory", tempDir.toPath().toString()) .build()) .build())) .disableEnvironmentVariablesSource() @@ -326,21 +309,19 @@ public void testSourceFromConfigByClass() throws Exception { assertThat(gitSource.gitEndpoint().path(), is("application.properties")); assertThat(gitSource.gitEndpoint().uri(), is(URI.create(fileUri()))); assertThat(gitSource.gitEndpoint().branch(), is("test")); - assertThat(gitSource.gitEndpoint().directory(), is(directory)); + assertThat(gitSource.gitEndpoint().directory(), is(tempDir.toPath())); } } @Test public void testSourceFromConfigByType() throws Exception { - Path directory = folder.newFolder().toPath(); - Config metaConfig = Config.builder(ConfigSources.create(ObjectNode.builder() .addValue("type", "git") .addObject("properties", ObjectNode.builder() .addValue("path", "application.properties") .addValue("uri", fileUri()) .addValue("branch", "test") - .addValue("directory", directory.toString()) + .addValue("directory", tempDir.toPath().toString()) .build()) .build())) .disableSystemPropertiesSource() @@ -351,7 +332,7 @@ public void testSourceFromConfigByType() throws Exception { assertThat(gitSource.gitEndpoint().path(), is("application.properties")); assertThat(gitSource.gitEndpoint().uri(), is(URI.create(fileUri()))); assertThat(gitSource.gitEndpoint().branch(), is("test")); - assertThat(gitSource.gitEndpoint().directory(), is(directory)); + assertThat(gitSource.gitEndpoint().directory(), is(tempDir.toPath())); } } } 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 index 4f34081888d..afbf3687435 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. + * 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. @@ -45,6 +45,7 @@ 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; @@ -68,8 +69,7 @@ public class FileServiceTest { @Test @Order(1) - public void testUpload(WebTarget target) throws IOException { - Path tempDirectory = Files.createTempDirectory(null); + 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)); diff --git a/reactive/webserver/static-content/src/test/java/io/helidon/reactive/webserver/staticcontent/FileSystemContentHandlerTest.java b/reactive/webserver/static-content/src/test/java/io/helidon/reactive/webserver/staticcontent/FileSystemContentHandlerTest.java index fc58a5871a1..52b78fc8276 100644 --- a/reactive/webserver/static-content/src/test/java/io/helidon/reactive/webserver/staticcontent/FileSystemContentHandlerTest.java +++ b/reactive/webserver/static-content/src/test/java/io/helidon/reactive/webserver/staticcontent/FileSystemContentHandlerTest.java @@ -16,6 +16,7 @@ package io.helidon.reactive.webserver.staticcontent; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -27,14 +28,12 @@ import io.helidon.common.http.Http; import io.helidon.common.media.type.MediaTypes; import io.helidon.reactive.webserver.Routing; -import io.helidon.reactive.webserver.testsupport.TemporaryFolder; -import io.helidon.reactive.webserver.testsupport.TemporaryFolderExtension; import io.helidon.reactive.webserver.testsupport.TestClient; import io.helidon.reactive.webserver.testsupport.TestResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -42,23 +41,23 @@ /** * Tests {@link FileSystemContentHandler}. */ -@ExtendWith(TemporaryFolderExtension.class) class FileSystemContentHandlerTest { - private TemporaryFolder folder; + @TempDir + File tempDir; @BeforeEach public void createContent() throws IOException { // root - Path root = folder.root().toPath(); + Path root = tempDir.toPath(); Files.writeString(root.resolve("index.html"), "Index HTML"); Files.writeString(root.resolve("foo.txt"), "Foo TXT"); // css - Path cssDir = folder.newFolder("css").toPath(); + Path cssDir = Files.createDirectory(tempDir.toPath().resolve("css")); Files.writeString(cssDir.resolve("a.css"), "A CSS"); Files.writeString(cssDir.resolve("b.css"), "B CSS"); // bar - Path other = folder.newFolder("other").toPath(); + Path other = Files.createDirectory(tempDir.toPath().resolve("other")); Files.writeString(other.resolve("index.html"), "Index HTML"); } @@ -73,7 +72,7 @@ static String responseToString(TestResponse response) @Test void serveFile() throws Exception { Routing routing = Routing.builder() - .register("/some", StaticContentSupport.create(folder.root().toPath())) + .register("/some", StaticContentSupport.create(tempDir.toPath())) .build(); // /some/foo.txt TestResponse response = TestClient.create(routing) @@ -109,7 +108,7 @@ void serveFile() throws Exception { @Test void serveIndex() throws Exception { Routing routing = Routing.builder() - .register(StaticContentSupport.builder(folder.root().toPath()) + .register(StaticContentSupport.builder(tempDir.toPath()) .welcomeFileName("index.html") .contentType("css", MediaTypes.TEXT_PLAIN) .build()) diff --git a/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolder.java b/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolder.java index ae51edfede6..96f8e980a05 100644 --- a/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolder.java +++ b/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolder.java @@ -29,6 +29,7 @@ /** * A helper class that represents a temporary folder. */ +@Deprecated public class TemporaryFolder { private File rootFolder; diff --git a/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolderExtension.java b/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolderExtension.java index 031c17f9653..6db4c695b12 100644 --- a/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolderExtension.java +++ b/reactive/webserver/test-support/src/main/java/io/helidon/reactive/webserver/testsupport/TemporaryFolderExtension.java @@ -33,6 +33,7 @@ * A JUnit5 extension to provide injection support of {@link TemporaryFolder} * instances. */ +@Deprecated public class TemporaryFolderExtension implements AfterEachCallback, TestInstancePostProcessor, ParameterResolver { From 74de234268d22f93f617d1880691c9481d567714 Mon Sep 17 00:00:00 2001 From: Daniel Kec Date: Thu, 24 Nov 2022 11:41:09 +0100 Subject: [PATCH 14/36] Kafka producer nacking fix 5510 (#5531) Signed-off-by: Daniel Kec --- .../connectors/kafka/KafkaSubscriber.java | 2 ++ .../connectors/kafka/AbstractSampleBean.java | 21 +++++++++++++++++++ .../connectors/kafka/KafkaMpTest.java | 19 +++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/messaging/connectors/kafka/src/main/java/io/helidon/messaging/connectors/kafka/KafkaSubscriber.java b/messaging/connectors/kafka/src/main/java/io/helidon/messaging/connectors/kafka/KafkaSubscriber.java index daa12e02083..d393bf639df 100644 --- a/messaging/connectors/kafka/src/main/java/io/helidon/messaging/connectors/kafka/KafkaSubscriber.java +++ b/messaging/connectors/kafka/src/main/java/io/helidon/messaging/connectors/kafka/KafkaSubscriber.java @@ -116,6 +116,8 @@ record = new ProducerRecord<>(topic, message.getPayload()); subscription.request(backpressure); } }); + } else { + message.nack(exception); } }); } diff --git a/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/AbstractSampleBean.java b/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/AbstractSampleBean.java index 8f57ca7fd22..ce6ce8d9bf2 100644 --- a/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/AbstractSampleBean.java +++ b/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/AbstractSampleBean.java @@ -24,12 +24,14 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Logger; import jakarta.enterprise.context.ApplicationScoped; +import io.helidon.common.reactive.Multi; import io.helidon.common.reactive.Single; import org.apache.kafka.clients.consumer.ConsumerRecord; @@ -305,4 +307,23 @@ public Message channel13ToChannel12(KafkaMessage msg) { return Message.of(msg.getPayload()); } } + + @ApplicationScoped + public static class Channel14 extends AbstractSampleBean { + + AtomicBoolean acked = new AtomicBoolean(); + CompletableFuture nacked = new CompletableFuture<>(); + + public CompletableFuture getNacked() { + return nacked; + } + + @Outgoing("test-channel-14") + public Multi> channel14() { + return Multi.just(Message.of("test", + () -> CompletableFuture.completedStage(null).thenRun(() -> acked.set(true)), + t -> CompletableFuture.completedFuture(null).thenAccept(v -> nacked.complete(t)) + )); + } + } } diff --git a/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaMpTest.java b/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaMpTest.java index 4660c1271a1..b91308dd660 100644 --- a/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaMpTest.java +++ b/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaMpTest.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; @@ -54,6 +55,7 @@ import org.apache.kafka.common.serialization.StringSerializer; import org.eclipse.microprofile.config.spi.ConfigProviderResolver; import org.eclipse.microprofile.reactive.messaging.spi.Connector; +import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -209,6 +211,13 @@ private static Map cdiConfig() { "mp.messaging.incoming.test-channel-13.group.id", "sameGroup", "mp.messaging.incoming.test-channel-13.key.deserializer", LongDeserializer.class.getName(), "mp.messaging.incoming.test-channel-13.value.deserializer", StringDeserializer.class.getName())); + p.putAll(Map.of( + "mp.messaging.outgoing.test-channel-14.connector", KafkaConnector.CONNECTOR_NAME, + "mp.messaging.outgoing.test-channel-14.max.block.ms", "100", + "mp.messaging.outgoing.test-channel-14.bootstrap.servers", KAFKA_SERVER, + "mp.messaging.outgoing.test-channel-14.topic", UNEXISTING_TOPIC, + "mp.messaging.outgoing.test-channel-14.key.serializer", LongSerializer.class.getName(), + "mp.messaging.outgoing.test-channel-14.value.serializer", StringSerializer.class.getName())); return p; } @@ -253,6 +262,7 @@ private static void cdiContainerUp() { classes.add(AbstractSampleBean.Channel9.class); classes.add(AbstractSampleBean.Channel11.class); classes.add(AbstractSampleBean.Channel12.class); + classes.add(AbstractSampleBean.Channel14.class); classes.add(MessagingCdiExtension.class); Map p = new HashMap<>(cdiConfig()); @@ -398,6 +408,15 @@ void kafkaSubscriberConnectionError() throws InterruptedException { kafkaResource.getKafkaTestUtils().consumeAllRecordsFromTopic(TEST_TOPIC_10); } + @Test + void kafkaProduceWithNack() throws InterruptedException, ExecutionException, TimeoutException { + LOGGER.fine(() -> "==========> test kafkaProduceWithNack()"); + AbstractSampleBean.Channel14 kafkaProdBean = cdiContainer.select(AbstractSampleBean.Channel14.class).get(); + Throwable t = kafkaProdBean.getNacked().get(5, TimeUnit.SECONDS); + assertNotNull(t); + assertThat(t.getCause(), Matchers.instanceOf(org.apache.kafka.common.errors.TimeoutException.class)); + } + @Test void kafkaSubscriberSendError() throws InterruptedException { LOGGER.fine(() -> "==========> test kafkaSubscriberSendError()"); From ba35447dc06b53e2c0aa435eaa6f9842d48326f8 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 24 Nov 2022 21:10:32 +0100 Subject: [PATCH 15/36] 4836 graalvm 22 4.x (#5378) * Upgrade GraalVM native image to 22.3.0 (#5308) * Introducing native image plugin from GraalVM * Support GraalVM 22.3 build * Update graalvm version in all relevant files. Signed-off-by: Tomas Langer * Upgrade GraalVM native image to 22.3.0 Signed-off-by: Tomas Langer --- applications/mp/pom.xml | 16 ++- applications/pom.xml | 35 ++++++ applications/se/pom.xml | 23 ++-- .../common/files/Dockerfile.native.mustache | 2 +- .../helidon-common/native-image.properties | 3 +- .../helidon-common/resource-config.json | 0 .../native-image/native-image.properties | 16 --- .../native-image.properties | 5 +- dependencies/pom.xml | 7 +- docs/includes/guides/graalnative.adoc | 2 +- etc/dependency-check-suppression.xml | 34 +++--- etc/scripts/includes/pipeline-env.sh | 2 +- .../neo4j/neo4j-mp/Dockerfile.native | 2 +- .../neo4j/neo4j-se/Dockerfile.native | 2 +- .../helidon-quickstart-mp/Dockerfile.native | 2 +- .../helidon-quickstart-mp/README.md | 2 +- .../helidon-quickstart-se/Dockerfile.native | 2 +- .../helidon-quickstart-se/README.md | 2 +- .../Dockerfile.native | 2 +- .../Dockerfile.native | 2 +- .../README.md | 2 +- .../helidon-grpc-core/native-image.properties | 3 +- .../native-image.properties | 6 +- .../native-image.properties | 8 +- .../native-image.properties | 2 +- .../resource-config.json | 0 .../native-image.properties | 6 +- integrations/db/h2/pom.xml | 4 +- .../ojdbc/jni-config.json | 6 -- .../ojdbc/native-image.properties | 39 ------- .../ojdbc/reflect-config.json | 78 -------------- .../ojdbc/resource-config.json | 15 --- integrations/db/pgsql/pom.xml | 4 +- .../graal/mp-native-image-extension/pom.xml | 5 - .../mp/nativeimage/extension/WeldFeature.java | 4 +- .../src/main/java/module-info.java | 1 - .../graal/native-image-extension/pom.xml | 5 - .../extension/HelidonReflectionFeature.java | 15 +-- .../src/main/java/module-info.java | 1 - .../native-image.properties | 2 +- .../reflect-config.json | 0 .../resource-config.json | 0 .../native-image.properties | 0 .../reflect-config.json | 0 .../native-image.properties | 1 - .../native-image.properties | 0 .../helidon-media-jsonp}/reflect-config.json | 0 messaging/connectors/kafka/pom.xml | 4 +- .../kafka/src/main/java/module-info.java | 2 +- .../native-image.properties | 2 +- .../native-image.properties | 13 +-- .../helidon-openapi/native-image.properties | 5 +- .../native-image.properties | 1 + .../native-image.properties | 0 .../resource-config.json | 0 .../native-image.properties | 0 .../reflect-config.json | 0 .../helidon/reactive/webclient/WebClient.java | 11 ++ .../reflect-config.json | 7 -- .../native-image.properties | 3 +- .../native-image.properties | 0 .../reflect-config.json | 0 .../native-image.properties | 3 +- .../helidon-security/native-image.properties | 11 +- tests/integration/native-image/mp-1/README.md | 1 - tests/integration/native-image/mp-1/pom.xml | 7 ++ tests/integration/native-image/mp-2/README.md | 2 +- tests/integration/native-image/mp-2/pom.xml | 32 ++---- .../tests/mp-2/native-image.properties | 20 ---- tests/integration/native-image/mp-3/pom.xml | 7 ++ .../META-INF/microprofile-config.properties | 1 - .../nativeimage/nima1/WebClientService.java | 2 +- tests/integration/native-image/se-1/pom.xml | 7 ++ .../nativeimage/se1/MockZipkinService.java | 3 +- .../nativeimage/se1/WebClientService.java | 4 +- .../native-image.properties | 3 +- .../reflect-config.json | 102 ------------------ .../native-image.properties | 2 +- .../native-image.properties | 5 + .../reflect-config.json | 0 80 files changed, 195 insertions(+), 433 deletions(-) rename common/common/src/main/resources/META-INF/native-image/{io.helidon => io.helidon.common}/helidon-common/native-image.properties (84%) rename common/common/src/main/resources/META-INF/native-image/{io.helidon => io.helidon.common}/helidon-common/resource-config.json (100%) delete mode 100644 config/encryption/src/main/resources/META-INF/native-image/native-image.properties rename integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/{io.helidon.integrations.cd => io.helidon.integrations.cdi}/helidon-integrations-cdi-jpa/native-image.properties (92%) rename integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/{io.helidon.integrations.cd => io.helidon.integrations.cdi}/helidon-integrations-cdi-jpa/resource-config.json (100%) delete mode 100644 integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/jni-config.json delete mode 100644 integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/native-image.properties delete mode 100644 integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/resource-config.json rename integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/{io.helidon/helidon => io.helidon.integrations.graal/helidon-graal-native-image-extension}/native-image.properties (95%) rename integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/{io.helidon/helidon => io.helidon.integrations.graal/helidon-graal-native-image-extension}/reflect-config.json (100%) rename integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/{io.helidon/helidon => io.helidon.integrations.graal/helidon-graal-native-image-extension}/resource-config.json (100%) rename jersey/jsonp/src/main/resources/META-INF/native-image/{io.helidon.jersey.media.jsonp => io.helidon.jersey}/helidon-jersey-media-jsonp/native-image.properties (100%) rename jersey/jsonp/src/main/resources/META-INF/native-image/{io.helidon.jersey.media.jsonp => io.helidon.jersey}/helidon-jersey-media-jsonp/reflect-config.json (100%) rename {nima/http/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.nima.http.media/helidon-nima-http-media-jsonp => media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp}/native-image.properties (100%) rename {nima/http/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.nima.http.media/helidon-nima-http-media-jsonp => media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp}/reflect-config.json (100%) rename metrics/metrics/src/main/resources/META-INF/native-image/io.helidon.metrics/{ => helidon-metrics}/native-image.properties (91%) rename reactive/media/jsonb/src/main/resources/META-INF/native-image/{io.helidon.media/helidon-meida-jsonb => io.helidon.reactive.media/helidon-reactive-media-jsonb}/native-image.properties (100%) rename reactive/media/jsonb/src/main/resources/META-INF/native-image/{io.helidon.media/helidon-meida-jsonb => io.helidon.reactive.media/helidon-reactive-media-jsonb}/resource-config.json (100%) rename reactive/media/jsonp/src/main/resources/META-INF/native-image/{io.helidon.media/helidon-media-jsonp-common => io.helidon.reactive.media/helidon-reactive-media-jsonp}/native-image.properties (100%) rename reactive/media/jsonp/src/main/resources/META-INF/native-image/{io.helidon.media/helidon-media-jsonp-common => io.helidon.reactive.media/helidon-reactive-media-jsonp}/reflect-config.json (100%) delete mode 100644 reactive/webserver/access-log/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-access-log/reflect-config.json rename reactive/webserver/webserver/src/main/resources/META-INF/native-image/{io.helidon.webserver/helidon-webserver => io.helidon.reactive.webserver/helidon-reactive-webserver}/native-image.properties (100%) rename reactive/webserver/webserver/src/main/resources/META-INF/native-image/{io.helidon.webserver/helidon-webserver => io.helidon.reactive.webserver/helidon-reactive-webserver}/reflect-config.json (100%) rename security/providers/oidc-common/src/main/resources/META-INF/native-image/{ => io.helidon.security.providers/helidon-security-providers-oidc-common}/native-image.properties (87%) delete mode 100644 tests/integration/native-image/mp-2/src/main/resources/META-INF/native-image/tests/mp-2/native-image.properties rename tracing/zipkin/src/main/resources/META-INF/native-image/{ => io.helidon.tracing/helidon-tracing-zipkin}/native-image.properties (93%) rename {reactive/webclient/jaxrs/src/main/resources/META-INF/native-image => webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs}/native-image.properties (67%) rename reactive/webclient/jaxrs/src/main/resources/META-INF/native-image/helidon-webclient-jaxrs-reflection-config.json => webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs/reflect-config.json (100%) diff --git a/applications/mp/pom.xml b/applications/mp/pom.xml index db4f079f344..ee1e9ff4d1d 100644 --- a/applications/mp/pom.xml +++ b/applications/mp/pom.xml @@ -83,14 +83,22 @@ - io.helidon.build-tools - helidon-maven-plugin + org.graalvm.buildtools + native-maven-plugin - native-image + resource-config + + generateResourceConfig + + package + + + build-native-image - native-image + compile + package diff --git a/applications/pom.xml b/applications/pom.xml index afe19d1c9ca..f0bb736d796 100644 --- a/applications/pom.xml +++ b/applications/pom.xml @@ -50,6 +50,7 @@ 3.0.0 3.0.0 3.0.2 + 0.9.16 1.5.0.Final 0.6.1 2.7 @@ -179,6 +180,40 @@ io.grpc:protoc-gen-grpc-java:${version.lib.grpc}:exe:${os.detected.classifier} + + org.graalvm.buildtools + native-maven-plugin + ${version.plugin.nativeimage} + + + resource-config + + + true + + + + build-native-image + + + true + + ${project.build.outputDirectory} + ${project.build.finalName} + false + + false + + + + --add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.configure=ALL-UNNAMED + --enable-preview + + + + + diff --git a/applications/se/pom.xml b/applications/se/pom.xml index 5c4f9ba65a7..5a86cc2b18b 100644 --- a/applications/se/pom.xml +++ b/applications/se/pom.xml @@ -36,21 +36,22 @@ - io.helidon.build-tools - helidon-maven-plugin - - - -J--enable-preview - -J--add-modules - -JALL-SYSTEM - - + org.graalvm.buildtools + native-maven-plugin - native-image + resource-config + + generateResourceConfig + + package + + + build-native-image - native-image + compile + package diff --git a/archetypes/helidon/src/main/archetype/common/files/Dockerfile.native.mustache b/archetypes/helidon/src/main/archetype/common/files/Dockerfile.native.mustache index 4846986fd2c..eb27cc0281c 100644 --- a/archetypes/helidon/src/main/archetype/common/files/Dockerfile.native.mustache +++ b/archetypes/helidon/src/main/archetype/common/files/Dockerfile.native.mustache @@ -1,6 +1,6 @@ # 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build +FROM ghcr.io/graalvm/graalvm-ce:ol9-java19-22.3.0 as build # Install native-image RUN gu install native-image diff --git a/common/common/src/main/resources/META-INF/native-image/io.helidon/helidon-common/native-image.properties b/common/common/src/main/resources/META-INF/native-image/io.helidon.common/helidon-common/native-image.properties similarity index 84% rename from common/common/src/main/resources/META-INF/native-image/io.helidon/helidon-common/native-image.properties rename to common/common/src/main/resources/META-INF/native-image/io.helidon.common/helidon-common/native-image.properties index 90fc3732c31..059f9251bf4 100644 --- a/common/common/src/main/resources/META-INF/native-image/io.helidon/helidon-common/native-image.properties +++ b/common/common/src/main/resources/META-INF/native-image/io.helidon.common/helidon-common/native-image.properties @@ -14,6 +14,5 @@ # limitations under the License. # -# All Helidon modules are designed to be initialized at build time -# (specific classes may be delayed to runtime) +# all Helidon classes should be designed for native image, exceptions configured in specific modules Args=--initialize-at-build-time=io.helidon diff --git a/common/common/src/main/resources/META-INF/native-image/io.helidon/helidon-common/resource-config.json b/common/common/src/main/resources/META-INF/native-image/io.helidon.common/helidon-common/resource-config.json similarity index 100% rename from common/common/src/main/resources/META-INF/native-image/io.helidon/helidon-common/resource-config.json rename to common/common/src/main/resources/META-INF/native-image/io.helidon.common/helidon-common/resource-config.json diff --git a/config/encryption/src/main/resources/META-INF/native-image/native-image.properties b/config/encryption/src/main/resources/META-INF/native-image/native-image.properties deleted file mode 100644 index 84549270225..00000000000 --- a/config/encryption/src/main/resources/META-INF/native-image/native-image.properties +++ /dev/null @@ -1,16 +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. -# -Args=--enable-all-security-services diff --git a/config/yaml/src/main/resources/META-INF/native-image/io.helidon.config/helidon-config-yaml/native-image.properties b/config/yaml/src/main/resources/META-INF/native-image/io.helidon.config/helidon-config-yaml/native-image.properties index 4a4ca04f076..30aecd85516 100644 --- a/config/yaml/src/main/resources/META-INF/native-image/io.helidon.config/helidon-config-yaml/native-image.properties +++ b/config/yaml/src/main/resources/META-INF/native-image/io.helidon.config/helidon-config-yaml/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 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. @@ -14,4 +14,5 @@ # limitations under the License. # -Args=--initialize-at-build-time=io.helidon.config.yaml +Args=--initialize-at-build-time=io.helidon.config.yaml \ + --initialize-at-build-time=org.yaml.snakeyaml diff --git a/dependencies/pom.xml b/dependencies/pom.xml index ec5a4b09012..8b14ce5825a 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -52,7 +52,7 @@ 1.33.3 2.3.3 3.21.7 - 21.3.0 + 22.3.0 17.4 17.1 2.9.0 @@ -978,11 +978,6 @@ - - org.graalvm.nativeimage - svm - ${version.lib.graalvm} - org.apache.kafka diff --git a/docs/includes/guides/graalnative.adoc b/docs/includes/guides/graalnative.adoc index 8bee202bc37..2d8116fe612 100644 --- a/docs/includes/guides/graalnative.adoc +++ b/docs/includes/guides/graalnative.adoc @@ -42,7 +42,7 @@ set the `GRAALVM_HOME` environment variable to point at your GraalVM installatio [source,bash] ---- # Your path might be different -export GRAALVM_HOME=/usr/local/graalvm-ce-21.3.0/Contents/Home/ +export GRAALVM_HOME=/usr/local/graalvm-ce-22.3.0/Contents/Home/ ---- Then install the optional `native-image` command: diff --git a/etc/dependency-check-suppression.xml b/etc/dependency-check-suppression.xml index b1674b71d2e..28ce28a2d35 100644 --- a/etc/dependency-check-suppression.xml +++ b/etc/dependency-check-suppression.xml @@ -18,119 +18,119 @@ --> ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21248 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21271 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21277 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21282 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21283 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21291 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21293 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21294 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21296 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21299 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21305 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21340 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21341 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21349 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21360 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21365 ^pkg:maven/org\.graalvm\..*/.*@.*$ CVE-2022-21366 diff --git a/etc/scripts/includes/pipeline-env.sh b/etc/scripts/includes/pipeline-env.sh index be39a5ed37c..3ee715af232 100644 --- a/etc/scripts/includes/pipeline-env.sh +++ b/etc/scripts/includes/pipeline-env.sh @@ -47,7 +47,7 @@ if [ -z "${__PIPELINE_ENV_INCLUDED__}" ]; then . ${WS_DIR}/etc/scripts/includes/error_handlers.sh if [ -z "${GRAALVM_HOME}" ]; then - export GRAALVM_HOME="/tools/graal-19-23" + export GRAALVM_HOME="/tools/graalvm-ce-java19-22.3.0" fi require_env() { diff --git a/examples/integrations/neo4j/neo4j-mp/Dockerfile.native b/examples/integrations/neo4j/neo4j-mp/Dockerfile.native index b189c0e8369..8b4b5a9f63e 100644 --- a/examples/integrations/neo4j/neo4j-mp/Dockerfile.native +++ b/examples/integrations/neo4j/neo4j-mp/Dockerfile.native @@ -15,7 +15,7 @@ # # 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build +FROM ghcr.io/graalvm/graalvm-ce:ol9-java19-22.3.0 as build # Install native-image RUN gu install native-image diff --git a/examples/integrations/neo4j/neo4j-se/Dockerfile.native b/examples/integrations/neo4j/neo4j-se/Dockerfile.native index 770f0acf859..cec6ac66574 100644 --- a/examples/integrations/neo4j/neo4j-se/Dockerfile.native +++ b/examples/integrations/neo4j/neo4j-se/Dockerfile.native @@ -15,7 +15,7 @@ # # 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build +FROM ghcr.io/graalvm/graalvm-ce:ol9-java19-22.3.0 as build # Install native-image RUN gu install native-image diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native index 4d44834f29f..c4470c1d57c 100644 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native +++ b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native @@ -15,7 +15,7 @@ # # 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build +FROM ghcr.io/graalvm/graalvm-ce:ol9-java19-22.3.0 as build # Install native-image RUN gu install native-image diff --git a/examples/quickstarts/helidon-quickstart-mp/README.md b/examples/quickstarts/helidon-quickstart-mp/README.md index 8305c86335b..4a025bd51e0 100644 --- a/examples/quickstarts/helidon-quickstart-mp/README.md +++ b/examples/quickstarts/helidon-quickstart-mp/README.md @@ -80,7 +80,7 @@ You can build a native executable in 2 different ways: ### Local build Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `21.3.0` or later. +version `22.3.0` or later. ``` # Setup the environment diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile.native b/examples/quickstarts/helidon-quickstart-se/Dockerfile.native index e6222cb4294..de40ef33a52 100644 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile.native +++ b/examples/quickstarts/helidon-quickstart-se/Dockerfile.native @@ -15,7 +15,7 @@ # # 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build +FROM ghcr.io/graalvm/graalvm-ce:ol9-java19-22.3.0 as build # Install native-image RUN gu install native-image diff --git a/examples/quickstarts/helidon-quickstart-se/README.md b/examples/quickstarts/helidon-quickstart-se/README.md index 183fb28eced..c3da9e6d54c 100644 --- a/examples/quickstarts/helidon-quickstart-se/README.md +++ b/examples/quickstarts/helidon-quickstart-se/README.md @@ -80,7 +80,7 @@ You can build a native executable in 2 different ways: ### Local build Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `21.3.0` or later. +version `22.3.0` or later. ``` # Setup the environment diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native index c61e11abcea..0cfa3515179 100644 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native +++ b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native @@ -15,7 +15,7 @@ # # 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build +FROM ghcr.io/graalvm/graalvm-ce:ol9-java19-22.3.0 as build # Install native-image RUN gu install native-image diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native index 229b28b84d6..46000ec91f8 100644 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native +++ b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native @@ -15,7 +15,7 @@ # # 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build +FROM ghcr.io/graalvm/graalvm-ce:ol9-java19-22.3.0 as build # Install native-image RUN gu install native-image diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/README.md b/examples/quickstarts/helidon-standalone-quickstart-se/README.md index 05b912e03d5..08887994d89 100644 --- a/examples/quickstarts/helidon-standalone-quickstart-se/README.md +++ b/examples/quickstarts/helidon-standalone-quickstart-se/README.md @@ -81,7 +81,7 @@ You can build a native executable in 2 different ways: ### Local build Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `21.3.0` or later. +version `22.3.0` or later. ``` # Setup the environment diff --git a/grpc/core/src/main/resources/META-INF/native-image/io-helidon-grpc/helidon-grpc-core/native-image.properties b/grpc/core/src/main/resources/META-INF/native-image/io-helidon-grpc/helidon-grpc-core/native-image.properties index b64704ec106..557a30ffa17 100644 --- a/grpc/core/src/main/resources/META-INF/native-image/io-helidon-grpc/helidon-grpc-core/native-image.properties +++ b/grpc/core/src/main/resources/META-INF/native-image/io-helidon-grpc/helidon-grpc-core/native-image.properties @@ -22,5 +22,4 @@ Args=--initialize-at-build-time=com.google \ --initialize-at-run-time=io.grpc.netty.Utils$ByteBufAllocatorPreferDirectHolder \ --initialize-at-run-time=io.grpc.netty.Utils$ByteBufAllocatorPreferHeapHolder \ --initialize-at-run-time=io.helidon.grpc.core.JsonbMarshaller \ - --initialize-at-run-time=io.helidon.grpc.server.SSLContextBuilder \ - --allow-incomplete-classpath + --initialize-at-run-time=io.helidon.grpc.server.SSLContextBuilder diff --git a/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-datasource-hikaricp/native-image.properties b/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-datasource-hikaricp/native-image.properties index ce6dd8f7b41..5901aa4594b 100644 --- a/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-datasource-hikaricp/native-image.properties +++ b/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-datasource-hikaricp/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Oracle and/or its affiliates. +# 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. @@ -14,4 +14,6 @@ # limitations under the License. # -Args=--initialize-at-run-time=com.zaxxer.hikari.metrics.dropwizard.CodaHaleMetricsTracker +Args=--initialize-at-build-time=com.zaxxer.hikari \ + --initialize-at-build-time=org.slf4j \ + --initialize-at-run-time=com.zaxxer.hikari.metrics.dropwizard.CodaHaleMetricsTracker diff --git a/integrations/cdi/hibernate-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-hibernate/native-image.properties b/integrations/cdi/hibernate-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-hibernate/native-image.properties index f1dab2d9b70..8f9df8f56ce 100644 --- a/integrations/cdi/hibernate-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-hibernate/native-image.properties +++ b/integrations/cdi/hibernate-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-hibernate/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Oracle and/or its affiliates. +# 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. @@ -14,5 +14,7 @@ # limitations under the License. # -Args=--initialize-at-run-time=org.hibernate.secure.internal.StandardJaccServiceImpl \ - --initialize-at-run-time=org.hibernate.dialect.OracleTypesHelper +Args=--initialize-at-build-time=org.hibernate \ + --initialize-at-build-time=org.antlr \ + --initialize-at-run-time=org.hibernate.secure.internal.StandardJaccServiceImpl \ + --initialize-at-run-time=org.hibernate.dialect diff --git a/integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cd/helidon-integrations-cdi-jpa/native-image.properties b/integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jpa/native-image.properties similarity index 92% rename from integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cd/helidon-integrations-cdi-jpa/native-image.properties rename to integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jpa/native-image.properties index a90c4e40123..d9eb58f5af5 100644 --- a/integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cd/helidon-integrations-cdi-jpa/native-image.properties +++ b/integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jpa/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Oracle and/or its affiliates. +# 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. diff --git a/integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cd/helidon-integrations-cdi-jpa/resource-config.json b/integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jpa/resource-config.json similarity index 100% rename from integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cd/helidon-integrations-cdi-jpa/resource-config.json rename to integrations/cdi/jpa-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jpa/resource-config.json diff --git a/integrations/cdi/jta-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jta/native-image.properties b/integrations/cdi/jta-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jta/native-image.properties index c66561f3a6e..9f03a961a9d 100644 --- a/integrations/cdi/jta-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jta/native-image.properties +++ b/integrations/cdi/jta-cdi/src/main/resources/META-INF/native-image/io.helidon.integrations.cdi/helidon-integrations-cdi-jta/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Oracle and/or its affiliates. +# 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. @@ -21,4 +21,6 @@ Args=--initialize-at-run-time=com.arjuna.ats.internal.jta.transaction.arjunacore --initialize-at-run-time=com.arjuna.ats.internal.arjuna.coordinator.ReaperWorkerThread \ --initialize-at-run-time=com.arjuna.ats.arjuna.recovery.RecoveryManager \ --initialize-at-run-time=com.arjuna.ats.internal.jta.resources.arjunacore.CommitMarkableResourceRecord \ - -H:IncludeResourceBundles=io.helidon.integrations.jta.cdi.Messages + --initialize-at-run-time=com.arjuna.ats.jdbc.TransactionalDriver \ + -H:IncludeResourceBundles=io.helidon.integrations.jta.cdi.Messages \ + --initialize-at-build-time=com.arjuna diff --git a/integrations/db/h2/pom.xml b/integrations/db/h2/pom.xml index c001b32f0be..f75b8f699da 100644 --- a/integrations/db/h2/pom.xml +++ b/integrations/db/h2/pom.xml @@ -48,8 +48,8 @@ h2 - org.graalvm.nativeimage - svm + org.graalvm.sdk + graal-sdk provided diff --git a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/jni-config.json b/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/jni-config.json deleted file mode 100644 index e903501a272..00000000000 --- a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/jni-config.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "name":"java.net.InetAddress", - "methods":[{"name":"","parameterTypes":[] }] - } -] \ No newline at end of file diff --git a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/native-image.properties b/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/native-image.properties deleted file mode 100644 index de101a41b82..00000000000 --- a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/native-image.properties +++ /dev/null @@ -1,39 +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. -# - -Args= --allow-incomplete-classpath \ - --enable-all-security-services \ - --initialize-at-build-time=oracle.net.jdbc.nl.mesg.NLSR_en \ - --initialize-at-build-time=oracle.jdbc.driver.DynamicByteArray \ - --initialize-at-build-time=oracle.sql.ConverterArchive \ - --initialize-at-build-time=oracle.sql.converter.CharacterConverterJDBC \ - --initialize-at-build-time=oracle.sql.converter.CharacterConverter1Byte \ - --initialize-at-run-time=oracle.jdbc.pool.OracleDataSource \ - --initialize-at-run-time=oracle.jdbc.driver.OracleDriver \ - --initialize-at-run-time=oracle.jdbc.driver.OracleTimeoutThreadPerVM \ - --initialize-at-run-time=oracle.jdbc.driver.BlockSource$ThreadedCachingBlockSource \ - --initialize-at-run-time=oracle.jdbc.driver.BlockSource$ThreadedCachingBlockSource$BlockReleaser \ - --initialize-at-run-time=oracle.security.o5logon.O5Logon \ - --initialize-at-run-time=oracle.net.nt.TimeoutInterruptHandler \ - --initialize-at-run-time=oracle.jdbc.driver.LogicalConnection \ - --initialize-at-run-time=oracle.jdbc.driver.NoSupportHAManager \ - --initialize-at-run-time=oracle.net.nt.Clock \ - --initialize-at-run-time=oracle.net.nt.TcpMultiplexer \ - --initialize-at-run-time=oracle.net.nt.TcpMultiplexer \ - --initialize-at-run-time=oracle.net.nt.TcpMultiplexer$LazyHolder \ - --initialize-at-run-time=oracle.jdbc.driver.SQLUtil$XMLFactory \ - --initialize-at-run-time=oracle.jdbc.driver.NamedTypeAccessor$XMLFactory \ - --initialize-at-run-time=oracle.xml.util.UnicodeUtil diff --git a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/reflect-config.json b/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/reflect-config.json index 4e460f36b8f..d628de76277 100644 --- a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/reflect-config.json +++ b/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/reflect-config.json @@ -1,82 +1,4 @@ [ - { - "name": "oracle.jdbc.internal.ACProxyable", - "methods": [ - { - "name": "setACProxy", - "parameterTypes": [ - "java.lang.Object" - ] - }, - { - "name": "getACProxy", - "parameterTypes": [] - } - ] - }, - { - "name": "oracle.jdbc.driver.T4CDriverExtension", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "name": "oracle.jdbc.driver.T2CDriverExtension", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "name": "oracle.net.ano.Ano", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "name": "oracle.net.ano.AuthenticationService", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "name": "oracle.net.ano.DataIntegrityService", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "name": "oracle.net.ano.EncryptionService", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "name": "oracle.net.ano.SupervisorService", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, { "name": "java.sql.Statement[]", "allDeclaredConstructors": true, diff --git a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/resource-config.json b/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/resource-config.json deleted file mode 100644 index 8ee1aead144..00000000000 --- a/integrations/db/ojdbc/src/main/resources/META-INF/native-image/io.helidon.integrations.db/ojdbc/resource-config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "resources":[ - {"pattern":"META-INF/services/java.sql.Driver"}, - {"pattern":"oracle/sql/converter_xcharset/.*.glb$"}, - {"pattern":"oracle/jdbc/defaultConnectionProperties.properties"}, - {"pattern":"oracle/jdbc/driver/errorMap.xml"}, - {"pattern":"oracle/jdbc/defaultLoggingConfig.properties"} - ], - "bundles": [ - {"name":"oracle.net.jdbc.nl.mesg.NLSR"}, - {"name":"oracle.net.mesg.Message"} - ] -} - - diff --git a/integrations/db/pgsql/pom.xml b/integrations/db/pgsql/pom.xml index 40c74de5066..71d439ab062 100644 --- a/integrations/db/pgsql/pom.xml +++ b/integrations/db/pgsql/pom.xml @@ -41,8 +41,8 @@ provided - org.graalvm.nativeimage - svm + org.graalvm.sdk + graal-sdk provided diff --git a/integrations/graal/mp-native-image-extension/pom.xml b/integrations/graal/mp-native-image-extension/pom.xml index 82af8d72051..faf1d69a3ed 100644 --- a/integrations/graal/mp-native-image-extension/pom.xml +++ b/integrations/graal/mp-native-image-extension/pom.xml @@ -56,11 +56,6 @@ graal-sdk provided - - org.graalvm.nativeimage - svm - provided - diff --git a/integrations/graal/mp-native-image-extension/src/main/java/io/helidon/integrations/graal/mp/nativeimage/extension/WeldFeature.java b/integrations/graal/mp-native-image-extension/src/main/java/io/helidon/integrations/graal/mp/nativeimage/extension/WeldFeature.java index b0455fcd8d2..0a183a46d24 100644 --- a/integrations/graal/mp-native-image-extension/src/main/java/io/helidon/integrations/graal/mp/nativeimage/extension/WeldFeature.java +++ b/integrations/graal/mp-native-image-extension/src/main/java/io/helidon/integrations/graal/mp/nativeimage/extension/WeldFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 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. @@ -33,7 +33,6 @@ import io.helidon.integrations.graal.nativeimage.extension.NativeConfig; -import com.oracle.svm.core.annotate.AutomaticFeature; import jakarta.enterprise.inject.spi.Bean; import jakarta.json.Json; import jakarta.json.JsonArray; @@ -51,7 +50,6 @@ * An automatic feature for native-image to * register Weld specific stuff. */ -@AutomaticFeature public class WeldFeature implements Feature { private static final boolean ENABLED = NativeConfig.option("weld.enable-feature", true); private static final boolean TRACE = NativeConfig.option("weld.trace", false); diff --git a/integrations/graal/mp-native-image-extension/src/main/java/module-info.java b/integrations/graal/mp-native-image-extension/src/main/java/module-info.java index 6b7f46287fc..3a237e3134d 100644 --- a/integrations/graal/mp-native-image-extension/src/main/java/module-info.java +++ b/integrations/graal/mp-native-image-extension/src/main/java/module-info.java @@ -18,7 +18,6 @@ */ module io.helidon.graal.nativeimage.mp { requires jakarta.cdi; - requires svm; requires io.helidon.graal.nativeimage; requires jakarta.json; requires org.graalvm.sdk; diff --git a/integrations/graal/native-image-extension/pom.xml b/integrations/graal/native-image-extension/pom.xml index df43bc31edd..12576c258ce 100644 --- a/integrations/graal/native-image-extension/pom.xml +++ b/integrations/graal/native-image-extension/pom.xml @@ -54,11 +54,6 @@ graal-sdk provided - - org.graalvm.nativeimage - svm - provided - 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 12bc3f0d4d2..0b8d4465edc 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 @@ -15,6 +15,7 @@ */ package io.helidon.integrations.graal.nativeimage.extension; +import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; @@ -37,13 +38,12 @@ import io.helidon.config.mp.MpConfigProviderResolver; import io.helidon.logging.common.LogConfig; -import com.oracle.svm.core.jdk.Resources; -import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; import io.github.classgraph.ClassGraph; import io.github.classgraph.ScanResult; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeProxyCreation; import org.graalvm.nativeimage.hosted.RuntimeReflection; +import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; /** * Feature to add reflection configuration to the image for Helidon, CDI and Jersey. @@ -280,7 +280,11 @@ private void processEntity(BeforeAnalysisContext context) { tracer.parsing(() -> "Processing annotated class " + aClass.getName()); String resourceName = aClass.getName().replace('.', '/') + ".class"; InputStream resourceStream = aClass.getClassLoader().getResourceAsStream(resourceName); - Resources.registerResource(resourceName, resourceStream); + try { + RuntimeResourceAccess.addResource(aClass.getModule(), resourceName, resourceStream.readAllBytes()); + } catch (IOException e) { + throw new RuntimeException("Failed to read entity class file", e); + } for (Field declaredField : aClass.getDeclaredFields()) { if (!Modifier.isPublic(declaredField.getModifiers()) && declaredField.getAnnotations().length == 0) { RuntimeReflection.register(declaredField); @@ -303,7 +307,6 @@ private void processRegisterRestClient(BeforeAnalysisContext context) { tracer.parsing(() -> "Looking up annotated by " + AT_REGISTER_REST_CLIENT); Set> annotatedSet = util.findAnnotated(AT_REGISTER_REST_CLIENT); - DynamicProxyRegistry proxyRegistry = ImageSingletons.lookup(DynamicProxyRegistry.class); Class autoCloseable = context.access().findClassByName("java.lang.AutoCloseable"); Class closeable = context.access().findClassByName("java.io.Closeable"); @@ -315,7 +318,7 @@ private void processRegisterRestClient(BeforeAnalysisContext context) { processClassHierarchy(context, it); // and we also need to create a proxy tracer.parsing(() -> "Registering a proxy for class " + it.getName()); - proxyRegistry.addProxyClass(it, autoCloseable, closeable); + RuntimeProxyCreation.register(it, autoCloseable, closeable); } }); } diff --git a/integrations/graal/native-image-extension/src/main/java/module-info.java b/integrations/graal/native-image-extension/src/main/java/module-info.java index 62fc60ca24e..64d69485941 100644 --- a/integrations/graal/native-image-extension/src/main/java/module-info.java +++ b/integrations/graal/native-image-extension/src/main/java/module-info.java @@ -22,7 +22,6 @@ requires io.helidon.logging.jul; requires io.github.classgraph; requires io.helidon.config.mp; - requires svm; requires org.graalvm.sdk; requires jakarta.json; diff --git a/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon/helidon/native-image.properties b/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon.integrations.graal/helidon-graal-native-image-extension/native-image.properties similarity index 95% rename from integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon/helidon/native-image.properties rename to integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon.integrations.graal/helidon-graal-native-image-extension/native-image.properties index fec0100d107..fc13fba03fd 100644 --- a/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon/helidon/native-image.properties +++ b/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon.integrations.graal/helidon-graal-native-image-extension/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 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. diff --git a/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon/helidon/reflect-config.json b/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon.integrations.graal/helidon-graal-native-image-extension/reflect-config.json similarity index 100% rename from integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon/helidon/reflect-config.json rename to integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon.integrations.graal/helidon-graal-native-image-extension/reflect-config.json diff --git a/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon/helidon/resource-config.json b/integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon.integrations.graal/helidon-graal-native-image-extension/resource-config.json similarity index 100% rename from integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon/helidon/resource-config.json rename to integrations/graal/native-image-extension/src/main/resources/META-INF/native-image/io.helidon.integrations.graal/helidon-graal-native-image-extension/resource-config.json diff --git a/jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey.media.jsonp/helidon-jersey-media-jsonp/native-image.properties b/jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey/helidon-jersey-media-jsonp/native-image.properties similarity index 100% rename from jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey.media.jsonp/helidon-jersey-media-jsonp/native-image.properties rename to jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey/helidon-jersey-media-jsonp/native-image.properties diff --git a/jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey.media.jsonp/helidon-jersey-media-jsonp/reflect-config.json b/jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey/helidon-jersey-media-jsonp/reflect-config.json similarity index 100% rename from jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey.media.jsonp/helidon-jersey-media-jsonp/reflect-config.json rename to jersey/jsonp/src/main/resources/META-INF/native-image/io.helidon.jersey/helidon-jersey-media-jsonp/reflect-config.json diff --git a/logging/log4j/src/main/resources/META-INF/native-image/io.helidon.logging/helidon-logging-log4j/native-image.properties b/logging/log4j/src/main/resources/META-INF/native-image/io.helidon.logging/helidon-logging-log4j/native-image.properties index 0480ffc97f9..dc75e1bb098 100644 --- a/logging/log4j/src/main/resources/META-INF/native-image/io.helidon.logging/helidon-logging-log4j/native-image.properties +++ b/logging/log4j/src/main/resources/META-INF/native-image/io.helidon.logging/helidon-logging-log4j/native-image.properties @@ -16,7 +16,6 @@ Args=-Dlog4j2.disable.jmx=true \ -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager \ - --allow-incomplete-classpath \ --report-unsupported-elements-at-runtime \ --initialize-at-build-time=org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration \ --initialize-at-build-time=org.apache.logging.log4j.core.config.status.StatusConfiguration \ diff --git a/nima/http/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.nima.http.media/helidon-nima-http-media-jsonp/native-image.properties b/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp/native-image.properties similarity index 100% rename from nima/http/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.nima.http.media/helidon-nima-http-media-jsonp/native-image.properties rename to media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp/native-image.properties diff --git a/nima/http/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.nima.http.media/helidon-nima-http-media-jsonp/reflect-config.json b/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp/reflect-config.json similarity index 100% rename from nima/http/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.nima.http.media/helidon-nima-http-media-jsonp/reflect-config.json rename to media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp/reflect-config.json diff --git a/messaging/connectors/kafka/pom.xml b/messaging/connectors/kafka/pom.xml index b642d6172af..28302166c18 100644 --- a/messaging/connectors/kafka/pom.xml +++ b/messaging/connectors/kafka/pom.xml @@ -65,8 +65,8 @@ true - org.graalvm.nativeimage - svm + org.graalvm.sdk + graal-sdk provided diff --git a/messaging/connectors/kafka/src/main/java/module-info.java b/messaging/connectors/kafka/src/main/java/module-info.java index 7640dc5f74f..b0494c5edbf 100644 --- a/messaging/connectors/kafka/src/main/java/module-info.java +++ b/messaging/connectors/kafka/src/main/java/module-info.java @@ -33,7 +33,7 @@ requires io.helidon.common.configurable; requires io.helidon.messaging; requires microprofile.config.api; - requires static svm; + requires static org.graalvm.sdk; requires java.security.sasl; requires transitive org.slf4j; // To allow KerberosLoginSubstitution diff --git a/metrics/metrics/src/main/resources/META-INF/native-image/io.helidon.metrics/native-image.properties b/metrics/metrics/src/main/resources/META-INF/native-image/io.helidon.metrics/helidon-metrics/native-image.properties similarity index 91% rename from metrics/metrics/src/main/resources/META-INF/native-image/io.helidon.metrics/native-image.properties rename to metrics/metrics/src/main/resources/META-INF/native-image/io.helidon.metrics/helidon-metrics/native-image.properties index 1c4245a3d37..4a39f5603d9 100644 --- a/metrics/metrics/src/main/resources/META-INF/native-image/io.helidon.metrics/native-image.properties +++ b/metrics/metrics/src/main/resources/META-INF/native-image/io.helidon.metrics/helidon-metrics/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Oracle and/or its affiliates. +# 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. diff --git a/microprofile/cdi/src/main/resources/META-INF/native-image/io.helidon.microprofile.cdi/helidon-microprofile-cdi/native-image.properties b/microprofile/cdi/src/main/resources/META-INF/native-image/io.helidon.microprofile.cdi/helidon-microprofile-cdi/native-image.properties index 1648ad8a7b9..37f73e723ec 100644 --- a/microprofile/cdi/src/main/resources/META-INF/native-image/io.helidon.microprofile.cdi/helidon-microprofile-cdi/native-image.properties +++ b/microprofile/cdi/src/main/resources/META-INF/native-image/io.helidon.microprofile.cdi/helidon-microprofile-cdi/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 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. @@ -14,10 +14,11 @@ # limitations under the License. # -# We need "report-unsupported-elements-at-runtime" - there is no fine grained control of this switch -Args=--initialize-at-build-time \ - --initialize-at-build-time=io.helidon.microprofile.cdi.BuildTimeInitializer \ +Args=--initialize-at-build-time=io.helidon.microprofile \ + --initialize-at-build-time=org.eclipse.microprofile \ + --initialize-at-build-time=jakarta \ + --initialize-at-build-time=org.jboss \ + --initialize-at-build-time=org.glassfish \ --initialize-at-run-time=org.jboss.weld.probe.Resource \ - --initialize-at-run-time=org.jboss.weld.probe.Resource$14 \ - --report-unsupported-elements-at-runtime + --initialize-at-run-time=org.jboss.weld.probe.Resource$14 diff --git a/openapi/src/main/resources/META-INF/native-image/io.helidon.openapi/helidon-openapi/native-image.properties b/openapi/src/main/resources/META-INF/native-image/io.helidon.openapi/helidon-openapi/native-image.properties index ce86039510f..d4458ccb1ee 100644 --- a/openapi/src/main/resources/META-INF/native-image/io.helidon.openapi/helidon-openapi/native-image.properties +++ b/openapi/src/main/resources/META-INF/native-image/io.helidon.openapi/helidon-openapi/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Oracle and/or its affiliates. +# 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. @@ -14,4 +14,5 @@ # limitations under the License. # -Args=--initialize-at-run-time=io.smallrye.openapi.runtime.io.OpenApiSerializer +Args=--initialize-at-run-time=io.smallrye.openapi.runtime.io.OpenApiSerializer \ + --initialize-at-build-time=io.smallrye.openapi diff --git a/reactive/dbclient/jdbc/src/main/resources/META-INF/native-image/io.helidon.dbclient/helidon-dbclient-jdbc/native-image.properties b/reactive/dbclient/jdbc/src/main/resources/META-INF/native-image/io.helidon.dbclient/helidon-dbclient-jdbc/native-image.properties index d504602a092..edd1cacc1f8 100644 --- a/reactive/dbclient/jdbc/src/main/resources/META-INF/native-image/io.helidon.dbclient/helidon-dbclient-jdbc/native-image.properties +++ b/reactive/dbclient/jdbc/src/main/resources/META-INF/native-image/io.helidon.dbclient/helidon-dbclient-jdbc/native-image.properties @@ -15,4 +15,5 @@ # Args= --initialize-at-build-time=org.slf4j \ + --initialize-at-build-time=com.zaxxer.hikari \ --initialize-at-run-time=com.zaxxer.hikari.metrics.dropwizard.CodaHaleMetricsTracker diff --git a/reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.media/helidon-meida-jsonb/native-image.properties b/reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonb/native-image.properties similarity index 100% rename from reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.media/helidon-meida-jsonb/native-image.properties rename to reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonb/native-image.properties diff --git a/reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.media/helidon-meida-jsonb/resource-config.json b/reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonb/resource-config.json similarity index 100% rename from reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.media/helidon-meida-jsonb/resource-config.json rename to reactive/media/jsonb/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonb/resource-config.json diff --git a/reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp-common/native-image.properties b/reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonp/native-image.properties similarity index 100% rename from reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp-common/native-image.properties rename to reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonp/native-image.properties diff --git a/reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp-common/reflect-config.json b/reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonp/reflect-config.json similarity index 100% rename from reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.media/helidon-media-jsonp-common/reflect-config.json rename to reactive/media/jsonp/src/main/resources/META-INF/native-image/io.helidon.reactive.media/helidon-reactive-media-jsonp/reflect-config.json diff --git a/reactive/webclient/webclient/src/main/java/io/helidon/reactive/webclient/WebClient.java b/reactive/webclient/webclient/src/main/java/io/helidon/reactive/webclient/WebClient.java index 86e02ec4616..ef640a2519c 100644 --- a/reactive/webclient/webclient/src/main/java/io/helidon/reactive/webclient/WebClient.java +++ b/reactive/webclient/webclient/src/main/java/io/helidon/reactive/webclient/WebClient.java @@ -367,6 +367,17 @@ public Builder addHeader(Http.HeaderName header, String... value) { return this; } + /** + * Add a default header (such as accept). + * + * @param headerValue header name and value + * @return updated builder instance + */ + public Builder addHeader(Http.HeaderValue headerValue) { + configuration.defaultHeader(headerValue); + return this; + } + /** * Sets base uri for each request. * diff --git a/reactive/webserver/access-log/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-access-log/reflect-config.json b/reactive/webserver/access-log/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-access-log/reflect-config.json deleted file mode 100644 index 813ae76effc..00000000000 --- a/reactive/webserver/access-log/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-access-log/reflect-config.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "name": "io.helidon.reactive.webserver.accesslog.AccessLogHandler", - "allDeclaredConstructors": true, - "allPublicMethods": true - } -] diff --git a/reactive/webserver/jersey/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-jersey/native-image.properties b/reactive/webserver/jersey/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-jersey/native-image.properties index 85c430e00de..908d056c147 100644 --- a/reactive/webserver/jersey/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-jersey/native-image.properties +++ b/reactive/webserver/jersey/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver-jersey/native-image.properties @@ -15,4 +15,5 @@ # Args=-H:EnableURLProtocols=http,https \ - --initialize-at-run-time=org.glassfish.jersey.client.internal.HttpUrlConnector + --initialize-at-run-time=org.glassfish.jersey.client.internal.HttpUrlConnector \ + --initialize-at-build-time=org.eclipse.yasson diff --git a/reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver/native-image.properties b/reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.reactive.webserver/helidon-reactive-webserver/native-image.properties similarity index 100% rename from reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver/native-image.properties rename to reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.reactive.webserver/helidon-reactive-webserver/native-image.properties diff --git a/reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver/reflect-config.json b/reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.reactive.webserver/helidon-reactive-webserver/reflect-config.json similarity index 100% rename from reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.webserver/helidon-webserver/reflect-config.json rename to reactive/webserver/webserver/src/main/resources/META-INF/native-image/io.helidon.reactive.webserver/helidon-reactive-webserver/reflect-config.json diff --git a/security/providers/oidc-common/src/main/resources/META-INF/native-image/native-image.properties b/security/providers/oidc-common/src/main/resources/META-INF/native-image/io.helidon.security.providers/helidon-security-providers-oidc-common/native-image.properties similarity index 87% rename from security/providers/oidc-common/src/main/resources/META-INF/native-image/native-image.properties rename to security/providers/oidc-common/src/main/resources/META-INF/native-image/io.helidon.security.providers/helidon-security-providers-oidc-common/native-image.properties index a840c5f2a37..14dc9dc2da9 100644 --- a/security/providers/oidc-common/src/main/resources/META-INF/native-image/native-image.properties +++ b/security/providers/oidc-common/src/main/resources/META-INF/native-image/io.helidon.security.providers/helidon-security-providers-oidc-common/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 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. @@ -16,5 +16,4 @@ Args=-H:EnableURLProtocols=http \ -H:EnableURLProtocols=https \ - --enable-all-security-services \ --initialize-at-build-time=io.helidon.security.providers.oidc.common diff --git a/security/security/src/main/resources/META-INF/native-image/io.helidon.security/helidon-security/native-image.properties b/security/security/src/main/resources/META-INF/native-image/io.helidon.security/helidon-security/native-image.properties index abc13ca74a8..9f1f44505e7 100644 --- a/security/security/src/main/resources/META-INF/native-image/io.helidon.security/helidon-security/native-image.properties +++ b/security/security/src/main/resources/META-INF/native-image/io.helidon.security/helidon-security/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 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. @@ -14,12 +14,5 @@ # limitations under the License. # -# -# Graal native image supports additional configuration from this property file. # Security Subject requires this to work -# The `all-security-services` is to support encryption algorithms, -# intermediate solution until we can figure out -# how to do a fine-grained algorithm support -# -Args=-H:IncludeResourceBundles=sun.security.util.Resources \ - --enable-all-security-services +Args=-H:IncludeResourceBundles=sun.security.util.Resources diff --git a/tests/integration/native-image/mp-1/README.md b/tests/integration/native-image/mp-1/README.md index 8dcf795171f..932a81d8b9e 100644 --- a/tests/integration/native-image/mp-1/README.md +++ b/tests/integration/native-image/mp-1/README.md @@ -35,7 +35,6 @@ ${GRAALVM_HOME}/bin/native-image -Dhelidon.native.reflection.trace-parsing=true -H:Name=helidon-tests-native-image-mp-1 \ "-H:IncludeResources=logging.properties|meta-config.yaml|web/resource.txt|web/welcome.txt|verify-jwk.json|META-INF/native-image/tests/mp-1/resource-config.json|META-INF/beans.xml|META-INF/microprofile-config.properties|sign-jwk.json" \ -H:+ReportExceptionStackTraces \ - --no-server \ -jar ./target/helidon-tests-native-image-mp-1.jar ``` diff --git a/tests/integration/native-image/mp-1/pom.xml b/tests/integration/native-image/mp-1/pom.xml index ff501d11e9a..95f1f512069 100644 --- a/tests/integration/native-image/mp-1/pom.xml +++ b/tests/integration/native-image/mp-1/pom.xml @@ -93,6 +93,13 @@ + + org.graalvm.buildtools + native-maven-plugin + + true + + diff --git a/tests/integration/native-image/mp-2/README.md b/tests/integration/native-image/mp-2/README.md index 75f0bdf7fc0..787287661e4 100644 --- a/tests/integration/native-image/mp-2/README.md +++ b/tests/integration/native-image/mp-2/README.md @@ -11,7 +11,7 @@ mvn clean package -Pnative-image ./target/helidon-tests-native-image-mp-2 ``` -Requires at least GraalVM 21.3.0 +Requires at least GraalVM 22.3.0 This test validates that JPA integration (using Hibernate) and JTA integration work in native image. diff --git a/tests/integration/native-image/mp-2/pom.xml b/tests/integration/native-image/mp-2/pom.xml index 4b8e371063c..4f16f368dc6 100644 --- a/tests/integration/native-image/mp-2/pom.xml +++ b/tests/integration/native-image/mp-2/pom.xml @@ -125,6 +125,13 @@ + + org.graalvm.buildtools + native-maven-plugin + + true + + org.jboss.jandex jandex-maven-plugin @@ -174,29 +181,4 @@ - - - native-image - - - - io.helidon.build-tools - helidon-maven-plugin - - ${mainClass} - main - - - - native-image - - native-image - - - - - - - - diff --git a/tests/integration/native-image/mp-2/src/main/resources/META-INF/native-image/tests/mp-2/native-image.properties b/tests/integration/native-image/mp-2/src/main/resources/META-INF/native-image/tests/mp-2/native-image.properties deleted file mode 100644 index 7abbaa30149..00000000000 --- a/tests/integration/native-image/mp-2/src/main/resources/META-INF/native-image/tests/mp-2/native-image.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. -# - -# -# Graal native image supports additional configuration from this property file. -# -Args=-H:+RemoveSaturatedTypeFlows diff --git a/tests/integration/native-image/mp-3/pom.xml b/tests/integration/native-image/mp-3/pom.xml index 8250dc1c191..ec2624107c7 100644 --- a/tests/integration/native-image/mp-3/pom.xml +++ b/tests/integration/native-image/mp-3/pom.xml @@ -53,6 +53,13 @@ + + org.graalvm.buildtools + native-maven-plugin + + true + + org.apache.maven.plugins maven-dependency-plugin diff --git a/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config.properties b/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config.properties index 1ef4e8f1dd7..2e4a439fa21 100644 --- a/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config.properties +++ b/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config.properties @@ -20,7 +20,6 @@ mp.config.profile=test app.greeting=Wrong Hello # Microprofile server properties -#server.port=7001 server.port=7001 server.host=0.0.0.0 %test.server.port=0 diff --git a/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/WebClientService.java b/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/WebClientService.java index 4b402ea6abc..b18a0a46e71 100644 --- a/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/WebClientService.java +++ b/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/WebClientService.java @@ -48,7 +48,7 @@ public WebClientService(Config config, MockZipkinService zipkinService) { client = WebClient.builder() .baseUri(context) // TODO: improvement - // .addHeader(Http.Header.ACCEPT, MediaTypes.APPLICATION_JSON.toString()) + // .addHeader(Http.Header.ACCEPT, MediaTypes.APPLICATION_JSON) // .config(config.get("client")) .build(); } diff --git a/tests/integration/native-image/se-1/pom.xml b/tests/integration/native-image/se-1/pom.xml index d027b072bc7..bb1615fbd40 100644 --- a/tests/integration/native-image/se-1/pom.xml +++ b/tests/integration/native-image/se-1/pom.xml @@ -127,6 +127,13 @@ + + org.graalvm.buildtools + native-maven-plugin + + true + + org.apache.maven.plugins maven-dependency-plugin diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/MockZipkinService.java b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/MockZipkinService.java index 23dfe3e90f5..8cb7853ab18 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/MockZipkinService.java +++ b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/MockZipkinService.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.StringReader; import java.nio.ByteBuffer; +import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -79,7 +80,7 @@ CompletionStage next() { } private void mockZipkin(final ServerRequest request, final ServerResponse response) { - request.queryParams().all("serviceName").forEach(s -> System.out.println(">>>" + s)); + request.queryParams().all("serviceName", List::of).forEach(s -> System.out.println(">>>" + s)); request.content() .registerReader(new MessageBodyStreamReader() { @Override diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebClientService.java b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebClientService.java index d10fb21439a..da9a64709fc 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebClientService.java +++ b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebClientService.java @@ -54,7 +54,7 @@ public WebClientService(Config config, MockZipkinService zipkinService) { client = WebClient.builder() .baseUri(context) .addReader(JsonbSupport.reader()) - .addHeader(Http.Header.ACCEPT, MediaTypes.APPLICATION_JSON.toString()) + .addHeader(Http.HeaderValues.ACCEPT_JSON) .config(config.get("client")) .build(); } @@ -96,7 +96,7 @@ private void getTest(final ServerRequest request, final ServerResponse response) response.status(Http.Status.INTERNAL_SERVER_ERROR_500); StringWriter writer = new StringWriter(); t.printStackTrace(new PrintWriter(writer)); - response.send("Failed to process request: " + writer.toString()); + response.send("Failed to process request: " + writer); } }); } diff --git a/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/native-image.properties b/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/native-image.properties index 56fb195a344..b0bdcb8a31d 100644 --- a/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/native-image.properties +++ b/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 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. @@ -16,6 +16,5 @@ Args=--initialize-at-build-time=org.slf4j,io.helidon.tracing.jaeger \ -H:+AddAllCharsets \ - --enable-all-security-services \ -H:EnableURLProtocols=http \ -H:EnableURLProtocols=https diff --git a/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/reflect-config.json b/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/reflect-config.json index a06752f7420..c37848ea954 100644 --- a/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/reflect-config.json +++ b/tracing/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-jaeger/reflect-config.json @@ -1,106 +1,4 @@ [ - { - "name": "io.jaegertracing.internal.samplers.http.SamplingStrategyResponse", - "allPublicConstructors": true, - "allDeclaredConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true, - "allPublicFields": true, - "allDeclaredFields": true, - "fields": [ - { - "name": "probabilisticSampling", - "allowWrite": true - }, - { - "name": "rateLimitingSampling", - "allowWrite": true - }, - { - "name": "operationSampling", - "allowWrite": true - } - ] - }, - { - "name": "io.jaegertracing.internal.metrics.Metrics", - "allPublicConstructors": true, - "allPublicMethods": true, - "allPublicFields": true, - "allDeclaredFields": true - }, - { - "name": "io.jaegertracing.internal.samplers.http.ProbabilisticSamplingStrategy", - "allPublicConstructors": true, - "allDeclaredConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true, - "allPublicFields": true, - "allDeclaredFields": true, - "fields": [ - { - "name": "samplingRate", - "allowWrite": true - } - ] - }, - { - "name": "io.jaegertracing.internal.samplers.http.RateLimitingSamplingStrategy", - "allPublicConstructors": true, - "allDeclaredConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true, - "allPublicFields": true, - "allDeclaredFields": true, - "fields": [ - { - "name": "maxTracesPerSecond", - "allowWrite": true - } - ] - }, - { - "name": "io.jaegertracing.internal.samplers.http.PerOperationSamplingParameters", - "allPublicConstructors": true, - "allDeclaredConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true, - "allPublicFields": true, - "allDeclaredFields": true, - "fields": [ - { - "name": "operation", - "allowWrite": true - }, - { - "name": "probabilisticSampling", - "allowWrite": true - } - ] - }, - { - "name": "io.jaegertracing.internal.samplers.http.OperationSamplingParameters", - "allPublicConstructors": true, - "allDeclaredConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true, - "allPublicFields": true, - "allDeclaredFields": true, - "fields": [ - { - "name": "defaultSamplingProbability", - "allowWrite": true - }, - { - "name": "defaultLowerBoundTracesPerSecond", - "allowWrite": true - }, - { - "name": "perOperationStrategies", - "allowWrite": true - } - ] - }, { "name": "java.time.Instant", "methods": [ diff --git a/tracing/zipkin/src/main/resources/META-INF/native-image/native-image.properties b/tracing/zipkin/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-zipkin/native-image.properties similarity index 93% rename from tracing/zipkin/src/main/resources/META-INF/native-image/native-image.properties rename to tracing/zipkin/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-zipkin/native-image.properties index c29a62f531c..c32396f5f67 100644 --- a/tracing/zipkin/src/main/resources/META-INF/native-image/native-image.properties +++ b/tracing/zipkin/src/main/resources/META-INF/native-image/io.helidon.tracing/helidon-tracing-zipkin/native-image.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 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. diff --git a/reactive/webclient/jaxrs/src/main/resources/META-INF/native-image/native-image.properties b/webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs/native-image.properties similarity index 67% rename from reactive/webclient/jaxrs/src/main/resources/META-INF/native-image/native-image.properties rename to webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs/native-image.properties index 5dcfae920d5..f537a9f3502 100644 --- a/reactive/webclient/jaxrs/src/main/resources/META-INF/native-image/native-image.properties +++ b/webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs/native-image.properties @@ -14,6 +14,11 @@ # limitations under the License. # +<<<<<<<< HEAD:reactive/webclient/jaxrs/src/main/resources/META-INF/native-image/native-image.properties Args=-H:ReflectionConfigurationResources=${.}/helidon-reactive-webclient-jaxrs-reflection-config.json \ -H:EnableURLProtocols=http \ --initialize-at-build-time=io.helidon.reactive.webclient.jaxrs +======== +Args=-H:EnableURLProtocols=http \ + --initialize-at-build-time=io.helidon.webclient.jaxrs +>>>>>>>> 4a4e044e9 (Upgrade GraalVM native image to 22.3.0 (#5308)):webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs/native-image.properties diff --git a/reactive/webclient/jaxrs/src/main/resources/META-INF/native-image/helidon-webclient-jaxrs-reflection-config.json b/webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs/reflect-config.json similarity index 100% rename from reactive/webclient/jaxrs/src/main/resources/META-INF/native-image/helidon-webclient-jaxrs-reflection-config.json rename to webclient/jaxrs/src/main/resources/META-INF/native-image/io.helidon.webclient/helidon-webclient-jaxrs/reflect-config.json From 22f67b0dcea826adb355f3665d19d07d21f6851d Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Mon, 28 Nov 2022 09:33:13 -0500 Subject: [PATCH 16/36] Tyrus integration into Nima (#5464) * Restored Tyrus module in Nima MP. Signed-off-by: Santiago Pericasgeertsen * Updated dependencies and socket routing code. Signed-off-by: Santiago Pericasgeertsen * Initial integration of Tyrus with Nima. Simple echo test works using the JDK's WS client. * Fixed checkstyle issues. Signed-off-by: Santiago Pericasgeertsen * Simplified TyrusConnection by not extending WsConnection. Restored some changes in Nima's WS module. * Some general code cleanup. Signed-off-by: Santiago Pericasgeertsen * Renamed some classes for consistency. Refactored tests for declarative and programmatic styles and to use @HelidonTest. * Support for @RoutingPath annotation. * Fixed checkstyle errors. * New test for extensions that uses the Tyrus client after fixes in Nima. * New test that combines REST and WS endpoint on same port. * Restored examples that use websockets. Signed-off-by: Santiago Pericasgeertsen * Order of protected fields and use putIfAbsent. Signed-off-by: Santiago Pericasgeertsen Signed-off-by: Santiago Pericasgeertsen --- examples/messaging/pom.xml | 8 +- examples/microprofile/pom.xml | 3 +- microprofile/pom.xml | 2 +- microprofile/websocket/pom.xml | 36 ++- .../tyrus/HelidonComponentProvider.java | 2 +- ...Application.java => TyrusApplication.java} | 28 +-- ...iExtension.java => TyrusCdiExtension.java} | 71 ++---- .../microprofile/tyrus/TyrusConnection.java | 173 +++++++++++++ .../microprofile/tyrus/TyrusRoute.java | 33 +++ .../microprofile/tyrus/TyrusRouting.java | 185 ++++++++++++++ .../tyrus/TyrusUpgradeProvider.java | 231 ++++++++++++++++++ .../websocket/src/main/java/module-info.java | 14 +- .../microprofile/tyrus/EchoClient.java | 2 +- .../microprofile/tyrus/EchoEndpoint.java | 52 ++++ .../tyrus/EchoEndpointBaseTest.java | 54 ++++ .../microprofile/tyrus/EchoEndpointProg.java | 58 +++++ ...AppTest.java => EchoEndpointProgTest.java} | 46 ++-- ...intTest.java => EchoEndpointRestTest.java} | 47 ++-- .../microprofile/tyrus/EchoEndpointTest.java | 47 ++++ .../microprofile/tyrus/EchoListener.java | 45 ++++ ...ntTest.java => ExtensionEndpointTest.java} | 44 +--- .../microprofile/tyrus/WebSocketBaseTest.java | 145 ----------- .../tyrus/WebSocketEndpointTest.java | 39 --- .../http1/Http1ConnectionProvider.java | 4 +- .../webserver/WsUpgradeProvider.java | 63 ++++- 25 files changed, 1072 insertions(+), 360 deletions(-) rename microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/{WebSocketApplication.java => TyrusApplication.java} (83%) rename microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/{WebSocketCdiExtension.java => TyrusCdiExtension.java} (80%) create mode 100644 microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusConnection.java create mode 100644 microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRoute.java create mode 100644 microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRouting.java create mode 100644 microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusUpgradeProvider.java create mode 100644 microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpoint.java create mode 100644 microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointBaseTest.java create mode 100644 microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointProg.java rename microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/{WebSocketEndpointAppTest.java => EchoEndpointProgTest.java} (61%) rename microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/{WebSocketRestEndpointTest.java => EchoEndpointRestTest.java} (62%) create mode 100644 microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointTest.java create mode 100644 microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoListener.java rename microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/{WebSocketExtensionEndpointTest.java => ExtensionEndpointTest.java} (61%) delete mode 100644 microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketBaseTest.java delete mode 100644 microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketEndpointTest.java diff --git a/examples/messaging/pom.xml b/examples/messaging/pom.xml index 307b452cd67..297f5f0521b 100644 --- a/examples/messaging/pom.xml +++ b/examples/messaging/pom.xml @@ -35,11 +35,9 @@ - - - kafka-websocket-se - + kafka-websocket-mp + jms-websocket-mp jms-websocket-se - + oracle-aq-websocket-mp diff --git a/examples/microprofile/pom.xml b/examples/microprofile/pom.xml index 10344981a19..94bd3d01ba6 100644 --- a/examples/microprofile/pom.xml +++ b/examples/microprofile/pom.xml @@ -41,8 +41,7 @@ multipart oidc openapi-basic - - + websocket messaging-sse cors tls diff --git a/microprofile/pom.xml b/microprofile/pom.xml index e8ff83c99ed..06ccd1b7098 100644 --- a/microprofile/pom.xml +++ b/microprofile/pom.xml @@ -49,7 +49,7 @@ grpc cdi weld - + websocket reactive-streams messaging cors diff --git a/microprofile/websocket/pom.xml b/microprofile/websocket/pom.xml index d70ef0c1bee..ddcc1d9bf07 100644 --- a/microprofile/websocket/pom.xml +++ b/microprofile/websocket/pom.xml @@ -32,7 +32,7 @@ Helidon MP integration with Tyrus - -Dmp.initializer.allow=true + -Dmp.initializer.allow=true --enable-preview @@ -41,8 +41,28 @@ helidon-microprofile-cdi - io.helidon.reactive.webserver - helidon-reactive-webserver-websocket + io.helidon.microprofile.server + helidon-microprofile-server + + + io.helidon.nima.webserver + helidon-nima-webserver + + + io.helidon.nima.websocket + helidon-nima-websocket-webserver + + + org.glassfish.tyrus + tyrus-core + + + org.glassfish.tyrus + tyrus-server + + + org.glassfish.tyrus + tyrus-container-jdk-client io.helidon.common @@ -68,8 +88,14 @@ test - io.helidon.microprofile.server - helidon-microprofile-server + org.glassfish.tyrus + tyrus-client + test + + + io.helidon.microprofile.tests + helidon-microprofile-tests-junit5 + test diff --git a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/HelidonComponentProvider.java b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/HelidonComponentProvider.java index 249e56af643..cd7b3960edb 100644 --- a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/HelidonComponentProvider.java +++ b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/HelidonComponentProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * 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. diff --git a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/WebSocketApplication.java b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusApplication.java similarity index 83% rename from microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/WebSocketApplication.java rename to microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusApplication.java index fa56d3ff750..398c952937c 100644 --- a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/WebSocketApplication.java +++ b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusApplication.java @@ -28,14 +28,14 @@ /** * Represents a websocket application with class and config endpoints. */ -public final class WebSocketApplication { +public final class TyrusApplication { - private Class applicationClass; - private Set> annotatedEndpoints; - private Set> programmaticEndpoints; - private Set extensions; + private final Class applicationClass; + private final Set> annotatedEndpoints; + private final Set> programmaticEndpoints; + private final Set extensions; - private WebSocketApplication(Builder builder) { + private TyrusApplication(Builder builder) { this.applicationClass = builder.applicationClass; this.annotatedEndpoints = builder.annotatedEndpoints; this.programmaticEndpoints = builder.programmaticEndpoints; @@ -43,7 +43,7 @@ private WebSocketApplication(Builder builder) { } /** - * A new fluent API builder to create a customized {@link WebSocketApplication}. + * A new fluent API builder to create a customized {@link TyrusApplication}. * * @return a new builder instance */ @@ -88,15 +88,15 @@ public Set extensions() { } /** - * Fluent API builder to create {@link WebSocketApplication} instances. + * Fluent API builder to create {@link TyrusApplication} instances. */ public static class Builder { - private static final Logger LOGGER = Logger.getLogger(WebSocketApplication.Builder.class.getName()); + private static final Logger LOGGER = Logger.getLogger(TyrusApplication.Builder.class.getName()); private Class applicationClass; - private Set> annotatedEndpoints = new HashSet<>(); - private Set> programmaticEndpoints = new HashSet<>(); - private Set extensions = new HashSet<>(); + private final Set> annotatedEndpoints = new HashSet<>(); + private final Set> programmaticEndpoints = new HashSet<>(); + private final Set extensions = new HashSet<>(); /** * Updates an application class in the builder. Clears all results from scanning. @@ -164,8 +164,8 @@ public Builder extension(Extension extension) { * * @return The application. */ - public WebSocketApplication build() { - return new WebSocketApplication(this); + public TyrusApplication build() { + return new TyrusApplication(this); } } } diff --git a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/WebSocketCdiExtension.java b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusCdiExtension.java similarity index 80% rename from microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/WebSocketCdiExtension.java rename to microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusCdiExtension.java index 9f5bed21f26..ae174128ba3 100644 --- a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/WebSocketCdiExtension.java +++ b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusCdiExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022 Oracle and/or its affiliates. + * 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. @@ -18,21 +18,17 @@ import java.util.Optional; import java.util.Set; -import java.util.concurrent.ExecutorService; import java.util.logging.Logger; -import io.helidon.common.configurable.ThreadPoolSupplier; import io.helidon.config.Config; import io.helidon.microprofile.cdi.RuntimeStart; import io.helidon.microprofile.server.RoutingName; import io.helidon.microprofile.server.RoutingPath; import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.reactive.webserver.WebServer; -import io.helidon.reactive.webserver.websocket.WebSocketRouting; +import io.helidon.nima.webserver.WebServer; import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.context.BeforeDestroyed; import jakarta.enterprise.context.Initialized; import jakarta.enterprise.event.Observes; import jakarta.enterprise.inject.UnsatisfiedResolutionException; @@ -51,17 +47,14 @@ /** * Configure Tyrus related things. */ -public class WebSocketCdiExtension implements Extension { - private static final Logger LOGGER = Logger.getLogger(WebSocketCdiExtension.class.getName()); - +public class TyrusCdiExtension implements Extension { + private static final Logger LOGGER = Logger.getLogger(TyrusCdiExtension.class.getName()); private static final String DEFAULT_WEBSOCKET_PATH = "/"; private Config config; - private ServerCdiExtension serverCdiExtension; - - private final WebSocketApplication.Builder appBuilder = WebSocketApplication.builder(); - private ExecutorService executorService; + private final TyrusApplication.Builder appBuilder = TyrusApplication.builder(); + private volatile TyrusRouting tyrusRouting; void prepareRuntime(@Observes @RuntimeStart Config config) { this.config = config; @@ -127,27 +120,22 @@ void extension(@Observes ProcessAnnotatedType "Extension does not have no-args constructor for " - + extension.getAnnotatedType().getJavaClass() + "! Skppping."); + + extension.getAnnotatedType().getJavaClass() + "! Skipping."); } catch (ReflectiveOperationException e) { throw new IllegalStateException("Unable to load WebSocket extension", e); } } - /** - * Provides access to websocket application. - * - * @return Application. - */ - WebSocketApplication toWebSocketApplication() { - return appBuilder.build(); + TyrusRouting tyrusRouting() { + return tyrusRouting; } private void registerWebSockets() { try { - WebSocketApplication app = toWebSocketApplication(); + TyrusApplication app = appBuilder.build(); // If application present call its methods - WebSocketRouting.Builder wsRoutingBuilder = WebSocketRouting.builder(); + TyrusRouting.Builder tyrusRoutingBuilder = TyrusRouting.builder(); Optional> appClass = app.applicationClass(); Optional contextRoot = appClass.flatMap(c -> findContextRoot(config, c)); @@ -158,12 +146,6 @@ private void registerWebSockets() { LOGGER.info("Registering websocket application at " + rootPath); - executorService = ThreadPoolSupplier.builder() - .threadNamePrefix("helidon-websocket-") - .build().get(); - - wsRoutingBuilder.executor(executorService); - if (appClass.isPresent()) { Class c = appClass.get(); @@ -189,34 +171,31 @@ private void registerWebSockets() { Set> endpointClasses = instance.getAnnotatedEndpointClasses(app.annotatedEndpoints()); // Register classes and configs - endpointClasses.forEach(aClass -> wsRoutingBuilder.endpoint(rootPath, aClass)); - endpointConfigs.forEach(wsCfg -> wsRoutingBuilder.endpoint(rootPath, wsCfg)); + endpointClasses.forEach(cl -> tyrusRoutingBuilder.endpoint(rootPath, cl)); + endpointConfigs.forEach(cf -> tyrusRoutingBuilder.endpoint(rootPath, cf)); // Create routing wsRoutingBuilder - addWsRouting(wsRoutingBuilder.build(), namedRouting, routingNameRequired, c.getName()); + tyrusRouting = tyrusRoutingBuilder.build(); + addWsRouting(tyrusRouting, namedRouting, routingNameRequired, c.getName()); } else { // Direct registration without calling application class - app.annotatedEndpoints().forEach(aClass -> wsRoutingBuilder.endpoint(rootPath, aClass)); - app.programmaticEndpoints().forEach(wsCfg -> wsRoutingBuilder.endpoint(rootPath, wsCfg)); - app.extensions().forEach(wsRoutingBuilder::extension); + app.annotatedEndpoints().forEach(cl -> tyrusRoutingBuilder.endpoint(rootPath, cl)); + app.programmaticEndpoints().forEach(ep -> tyrusRoutingBuilder.endpoint(rootPath, ep)); + app.extensions().forEach(tyrusRoutingBuilder::extension); // Create routing wsRoutingBuilder - serverCdiExtension.serverBuilder().addRouting(wsRoutingBuilder.build()); + tyrusRouting = tyrusRoutingBuilder.build(); + serverCdiExtension.serverBuilder().addRouting(tyrusRouting); } - } catch (IllegalArgumentException e) { throw new RuntimeException("Unable to load WebSocket extension", e); } } - void terminate(@Observes @BeforeDestroyed(ApplicationScoped.class) Object event) { - executorService.shutdown(); - } - - private void addWsRouting(WebSocketRouting routing, - Optional namedRouting, - boolean routingNameRequired, - String appName) { + private void addWsRouting(TyrusRouting routing, + Optional namedRouting, + boolean routingNameRequired, + String appName) { WebServer.Builder serverBuilder = serverCdiExtension.serverBuilder(); if (namedRouting.isPresent()) { String socket = namedRouting.get(); @@ -234,7 +213,7 @@ private void addWsRouting(WebSocketRouting routing, serverBuilder.addRouting(routing); } } else { - serverBuilder.addNamedRouting(socket, routing); + serverBuilder.routerBuilder(socket).addRouting(routing); } } else { serverBuilder.addRouting(routing); diff --git a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusConnection.java b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusConnection.java new file mode 100644 index 00000000000..6adc62ea47f --- /dev/null +++ b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusConnection.java @@ -0,0 +1,173 @@ +/* + * 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.microprofile.tyrus; + +import java.nio.ByteBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import io.helidon.common.buffers.BufferData; +import io.helidon.common.buffers.DataReader; +import io.helidon.nima.webserver.ConnectionContext; +import io.helidon.nima.webserver.spi.ServerConnection; +import io.helidon.nima.websocket.CloseCodes; +import io.helidon.nima.websocket.WsListener; +import io.helidon.nima.websocket.WsSession; + +import jakarta.websocket.CloseReason; +import org.glassfish.tyrus.spi.CompletionHandler; +import org.glassfish.tyrus.spi.Connection; +import org.glassfish.tyrus.spi.WebSocketEngine; +import org.glassfish.tyrus.spi.Writer; + +import static jakarta.websocket.CloseReason.CloseCodes.UNEXPECTED_CONDITION; +import static jakarta.websocket.CloseReason.CloseCodes.getCloseCode; + +/** + * A server connection that passes and receives buffers from Tyrus. Note that this + * connection does not handle framing, it simply passes raw bytes to Tyrus where + * that takes place. + */ +class TyrusConnection implements ServerConnection, WsSession { + private static final Logger LOGGER = Logger.getLogger(TyrusConnection.class.getName()); + + private final ConnectionContext ctx; + private final WebSocketEngine.UpgradeInfo upgradeInfo; + private final TyrusListener listener; + + TyrusConnection(ConnectionContext ctx, WebSocketEngine.UpgradeInfo upgradeInfo) { + this.ctx = ctx; + this.upgradeInfo = upgradeInfo; + this.listener = new TyrusListener(); + } + + @Override + public void handle() { + DataReader dataReader = ctx.dataReader(); + listener.onOpen(this); + while (true) { + try { + BufferData buffer = dataReader.readBuffer(); + listener.receive(this, buffer, true); + } catch (Exception e) { + listener.onError(this, e); + listener.onClose(this, CloseCodes.UNEXPECTED_CONDITION, e.getMessage()); + return; + } + } + } + + @Override + public WsSession send(String text, boolean last) { + return this; + } + + @Override + public WsSession send(BufferData bufferData, boolean last) { + return this; + } + + @Override + public WsSession ping(BufferData bufferData) { + return this; + } + + @Override + public WsSession pong(BufferData bufferData) { + return this; + } + + @Override + public WsSession close(int code, String reason) { + return this; + } + + @Override + public WsSession abort() { + return this; + } + + class TyrusListener implements WsListener { + private static final int MAX_RETRIES = 5; + + private Connection connection; + + @Override + public void receive(WsSession session, String text, boolean last) { + // Should never be called! + } + + @Override + public void receive(WsSession session, BufferData buffer, boolean last) { + byte[] b = new byte[buffer.available()]; + buffer.read(b); // buffer copy! + writeToTyrus(session, ByteBuffer.wrap(b)); + } + + @Override + public void onClose(WsSession session, int status, String reason) { + connection.close(new CloseReason(getCloseCode(status), reason)); + } + + @Override + public void onError(WsSession session, Throwable t) { + connection.close(new CloseReason(UNEXPECTED_CONDITION, t.getMessage())); + } + + @Override + public void onOpen(WsSession session) { + Writer writer = new Writer() { + @Override + public void close() { + } + + @Override + public void write(ByteBuffer byteBuffer, CompletionHandler completionHandler) { + byte[] b = new byte[byteBuffer.remaining()]; + byteBuffer.get(b); // buffer copy! + ctx.dataWriter().writeNow(BufferData.create(b)); // direct write to ctx + completionHandler.completed(byteBuffer); + } + }; + connection = upgradeInfo.createConnection(writer, TyrusListener::close); + } + + /** + * Writes a buffer to Tyrus. May retry a few times given that Tyrus may + * not be able to read all bytes at once. + * + * @param session the session + * @param nioBuffer the buffer to write + */ + private void writeToTyrus(WsSession session, ByteBuffer nioBuffer) { + int retries = MAX_RETRIES; + while (nioBuffer.remaining() > 0 && retries-- > 0) { + connection.getReadHandler().handle(nioBuffer); + } + + // If we can't push all data to Tyrus, cancel and report problem + if (retries == 0) { + String reason = "Tyrus did not consume all data after " + MAX_RETRIES + " retries"; + connection.close(new CloseReason(UNEXPECTED_CONDITION, reason)); + } + } + + private static void close(CloseReason closeReason) { + LOGGER.log(Level.FINE, () -> "Connection closed: " + closeReason); + } + } +} diff --git a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRoute.java b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRoute.java new file mode 100644 index 00000000000..40714c74495 --- /dev/null +++ b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRoute.java @@ -0,0 +1,33 @@ +/* + * 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.microprofile.tyrus; + +import io.helidon.common.http.HttpPrologue; +import io.helidon.common.http.PathMatcher; +import io.helidon.common.http.PathMatchers; + +import jakarta.websocket.server.ServerEndpointConfig; + +record TyrusRoute(String path, + Class endpointClass, + ServerEndpointConfig serverEndpointConfig, + PathMatcher pathMatcher) { + + PathMatchers.MatchResult accepts(HttpPrologue prologue) { + return pathMatcher.match(prologue.uriPath()); + } +} diff --git a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRouting.java b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRouting.java new file mode 100644 index 00000000000..69ae4892255 --- /dev/null +++ b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusRouting.java @@ -0,0 +1,185 @@ +/* + * 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.microprofile.tyrus; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import io.helidon.common.http.HttpPrologue; +import io.helidon.common.http.PathMatchers; +import io.helidon.nima.webserver.Routing; + +import jakarta.websocket.Extension; +import jakarta.websocket.server.ServerEndpoint; +import jakarta.websocket.server.ServerEndpointConfig; + +/** + * Routing class for Tyrus. + */ +public class TyrusRouting implements Routing { + private static final TyrusRouting EMPTY = TyrusRouting.builder().build(); + + private final Set extensions; + private final List routes; + + private TyrusRouting(Builder builder) { + this.routes = builder.routes; + this.extensions = builder.extensions; + } + + /** + * Builder for WebSocket routing. + * + * @return new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Emtpy WebSocket routing. + * + * @return empty routing + */ + public static TyrusRouting empty() { + return EMPTY; + } + + Set extensions() { + return extensions; + } + + List routes() { + return routes; + } + + /** + * Returns {@code true} if this route corresponds to one of the registered or + * discovered WS endpoint. + * + * @param prologue HTTP prologue + * @return outcome of test + */ + TyrusRoute findRoute(HttpPrologue prologue) { + for (TyrusRoute route : routes) { + PathMatchers.MatchResult accepts = route.accepts(prologue); + if (accepts.accepted()) { + return route; + } + } + return null; + } + + /** + * Fluent API builder for {@link TyrusRouting}. + */ + public static class Builder implements io.helidon.common.Builder { + + private final List routes = new ArrayList<>(); + private final Set extensions = new HashSet<>(); // mutable + + private Builder() { + } + + /** + * Add endpoint. + * + * @param path path of the endpoint + * @param endpointClass annotated endpoint class + * @return updated builder + */ + public Builder endpoint(String path, Class endpointClass) { + this.routes.add(new TyrusRoute(path, endpointClass, null, + PathMatchers.pattern(pathConcat(path, serverEndpoint(endpointClass))))); + return this; + } + + /** + * Add endpoint. + * + * @param endpointClass annotated endpoint class + * @return updated builder + */ + public Builder endpoint(Class endpointClass) { + return endpoint("/", endpointClass); + } + + /** + * Add endpoint. + * + * @param path path of the endpoint + * @param serverEndpointConfig Jakarta WebSocket endpoint configuration + * @return updated builder + */ + public Builder endpoint(String path, ServerEndpointConfig serverEndpointConfig) { + this.routes.add(new TyrusRoute(path, null, serverEndpointConfig, + PathMatchers.pattern(pathConcat(path, serverEndpointConfig.getPath())))); + return this; + } + + /** + * Add endpoint. + * + * @param serverEndpointConfig Jakarta WebSocket endpoint configuration + * @return updated builder + */ + public Builder endpoint(ServerEndpointConfig serverEndpointConfig) { + return endpoint("/", serverEndpointConfig); + } + + /** + * Add Jakarta WebSocket extension. + * + * @param extension Jakarta WebSocket extension + * @return updated builder + */ + public Builder extension(Extension extension) { + this.extensions.add(extension); + return this; + } + + @Override + public TyrusRouting build() { + return new TyrusRouting(this); + } + + private static String pathConcat(String rootPath, String path) { + StringBuilder result = new StringBuilder(); + if (rootPath.equals("/")) { + rootPath = ""; + } else if (!rootPath.startsWith("/")) { + result.append("/"); + } + result.append(rootPath); + if (!rootPath.endsWith("/") && !path.startsWith("/")) { + result.append("/"); + } + result.append(path); + return result.toString(); + } + + private static String serverEndpoint(Class endpointClass) { + ServerEndpoint annot = endpointClass.getAnnotation(ServerEndpoint.class); + if (annot == null) { + throw new IllegalArgumentException("Endpoint class " + endpointClass.getName() + + " missing @ServerEndpoint"); + } + return annot.value(); + } + } +} diff --git a/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusUpgradeProvider.java b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusUpgradeProvider.java new file mode 100644 index 00000000000..8d6acdcb23d --- /dev/null +++ b/microprofile/websocket/src/main/java/io/helidon/microprofile/tyrus/TyrusUpgradeProvider.java @@ -0,0 +1,231 @@ +/* + * 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.microprofile.tyrus; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import io.helidon.common.Weight; +import io.helidon.common.Weighted; +import io.helidon.common.buffers.BufferData; +import io.helidon.common.buffers.DataWriter; +import io.helidon.common.http.DirectHandler; +import io.helidon.common.http.Http; +import io.helidon.common.http.HttpPrologue; +import io.helidon.common.http.RequestException; +import io.helidon.common.http.WritableHeaders; +import io.helidon.common.uri.UriQuery; +import io.helidon.nima.webserver.ConnectionContext; +import io.helidon.nima.webserver.spi.ServerConnection; +import io.helidon.nima.websocket.webserver.WsUpgradeProvider; + +import jakarta.enterprise.inject.spi.CDI; +import jakarta.websocket.DeploymentException; +import jakarta.websocket.Extension; +import jakarta.websocket.server.ServerEndpointConfig; +import org.glassfish.tyrus.core.RequestContext; +import org.glassfish.tyrus.core.TyrusUpgradeResponse; +import org.glassfish.tyrus.core.TyrusWebSocketEngine; +import org.glassfish.tyrus.server.TyrusServerContainer; +import org.glassfish.tyrus.spi.WebSocketEngine; + +/** + * Tyrus connection upgrade provider. + */ +@Weight(Weighted.DEFAULT_WEIGHT + 100) // higher than base class +public class TyrusUpgradeProvider extends WsUpgradeProvider { + private static final Logger LOGGER = Logger.getLogger(TyrusUpgradeProvider.class.getName()); + + private String path; + private String queryString; + private final TyrusRouting tyrusRouting; + private final WebSocketEngine engine; + + /** + * @deprecated This constructor is only to be used by {@link java.util.ServiceLoader}. + */ + @Deprecated() + public TyrusUpgradeProvider() { + TyrusCdiExtension extension = CDI.current().select(TyrusCdiExtension.class).get(); + Objects.requireNonNull(extension); + this.tyrusRouting = extension.tyrusRouting(); + TyrusServerContainer tyrusServerContainer = initializeTyrus(); + this.engine = tyrusServerContainer.getWebSocketEngine(); + } + + @Override + public ServerConnection upgrade(ConnectionContext ctx, HttpPrologue prologue, WritableHeaders headers) { + // Check required header + String wsKey; + if (headers.contains(WS_KEY)) { + wsKey = headers.get(WS_KEY).value(); + } else { + // this header is required + return null; + } + + // Verify protocol version + String version; + if (headers.contains(WS_VERSION)) { + version = headers.get(WS_VERSION).value(); + } else { + version = SUPPORTED_VERSION; + } + if (!SUPPORTED_VERSION.equals(version)) { + throw RequestException.builder() + .type(DirectHandler.EventType.BAD_REQUEST) + .message("Unsupported WebSocket Version") + .header(SUPPORTED_VERSION_HEADER) + .build(); + } + + // Initialize path and queryString + path = prologue.uriPath().path(); + int k = path.indexOf('?'); + if (k > 0) { + this.path = path.substring(0, k); + this.queryString = path.substring(k + 1); + } else { + this.queryString = ""; + } + + // Check if this a Tyrus route exists + TyrusRoute route = ctx.router() + .routing(TyrusRouting.class, tyrusRouting) + .findRoute(prologue); + if (route == null) { + return null; + } + + // Validate origin + if (!anyOrigin()) { + if (headers.contains(Http.Header.ORIGIN)) { + String origin = headers.get(Http.Header.ORIGIN).value(); + if (!origins().contains(origin)) { + throw RequestException.builder() + .message("Invalid Origin") + .type(DirectHandler.EventType.FORBIDDEN) + .build(); + } + } + } + + // Protocol handshake with Tyrus + WebSocketEngine.UpgradeInfo upgradeInfo = protocolHandshake(headers); + + // todo support subprotocols (must be provided by route) + // Sec-WebSocket-Protocol: sub-protocol (list provided in PROTOCOL header, separated by comma space + DataWriter dataWriter = ctx.dataWriter(); + String switchingProtocols = SWITCHING_PROTOCOL_PREFIX + hash(ctx, wsKey) + SWITCHING_PROTOCOLS_SUFFIX; + dataWriter.write(BufferData.create(switchingProtocols.getBytes(StandardCharsets.US_ASCII))); + + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Upgraded to websocket version " + version); + } + return new TyrusConnection(ctx, upgradeInfo); + } + + TyrusServerContainer initializeTyrus() { + Set> allEndpointClasses = tyrusRouting.routes() + .stream() + .map(TyrusRoute::endpointClass) + .collect(Collectors.toSet()); + + TyrusServerContainer tyrusServerContainer = new TyrusServerContainer(allEndpointClasses) { + private final WebSocketEngine engine = + TyrusWebSocketEngine.builder(this).build(); + + @Override + public void register(Class endpointClass) { + throw new UnsupportedOperationException("Cannot register endpoint class"); + } + + @Override + public void register(ServerEndpointConfig serverEndpointConfig) { + throw new UnsupportedOperationException("Cannot register ServerEndpointConfig"); + } + + @Override + public Set getInstalledExtensions() { + return tyrusRouting.extensions(); + } + + @Override + public WebSocketEngine getWebSocketEngine() { + return engine; + } + }; + + // Register classes with context path "/" + WebSocketEngine engine = tyrusServerContainer.getWebSocketEngine(); + tyrusRouting.routes().forEach(route -> { + try { + if (route.serverEndpointConfig() != null) { + LOGGER.log(Level.FINE, () -> "Registering ws endpoint " + + route.path() + + route.serverEndpointConfig().getPath()); + engine.register(route.serverEndpointConfig(), route.path()); + } else { + LOGGER.log(Level.FINE, () -> "Registering annotated ws endpoint " + route.path()); + engine.register(route.endpointClass(), route.path()); + } + } catch (DeploymentException e) { + throw new RuntimeException(e); + } + }); + + return tyrusServerContainer; + } + + WebSocketEngine.UpgradeInfo protocolHandshake(WritableHeaders headers) { + LOGGER.log(Level.FINE, "Initiating WebSocket handshake with Tyrus..."); + + // Create Tyrus request context, copy request headers and query params + Map paramsMap = new HashMap<>(); + UriQuery uriQuery = UriQuery.create(queryString); + for (String name : uriQuery.names()) { + paramsMap.put(name, uriQuery.all(name).toArray(new String[0])); + } + RequestContext requestContext = RequestContext.Builder.create() + .requestURI(URI.create(path)) // excludes context path + .queryString(queryString) + .parameterMap(paramsMap) + .build(); + headers.forEach(e -> requestContext.getHeaders().put(e.name(), List.of(e.values()))); + + // Use Tyrus to process a WebSocket upgrade request + final TyrusUpgradeResponse upgradeResponse = new TyrusUpgradeResponse(); + final WebSocketEngine.UpgradeInfo upgradeInfo = engine.upgrade(requestContext, upgradeResponse); + + // Map Tyrus response headers back to Nima + upgradeResponse.getHeaders() + .forEach((key, value) -> headers.add( + Http.Header.create( + Http.Header.createName(key, key.toLowerCase(Locale.ROOT)), + value))); + return upgradeInfo; + } +} diff --git a/microprofile/websocket/src/main/java/module-info.java b/microprofile/websocket/src/main/java/module-info.java index fadb5fc1a23..7939a2a6d02 100644 --- a/microprofile/websocket/src/main/java/module-info.java +++ b/microprofile/websocket/src/main/java/module-info.java @@ -19,6 +19,7 @@ */ module io.helidon.microprofile.tyrus { requires java.logging; + requires java.net.http; requires jakarta.inject; requires jakarta.interceptor.api; @@ -29,15 +30,22 @@ requires io.helidon.config; requires io.helidon.microprofile.cdi; requires io.helidon.microprofile.server; - requires io.helidon.reactive.webserver.websocket; + requires io.helidon.nima.webserver; + requires io.helidon.nima.websocket.webserver; requires org.glassfish.tyrus.core; + requires org.glassfish.tyrus.server; + requires org.glassfish.tyrus.spi; exports io.helidon.microprofile.tyrus; // this is needed for CDI extensions that use non-public observer methods opens io.helidon.microprofile.tyrus to weld.core.impl, io.helidon.microprofile.cdi; - provides jakarta.enterprise.inject.spi.Extension with io.helidon.microprofile.tyrus.WebSocketCdiExtension; - provides org.glassfish.tyrus.core.ComponentProvider with io.helidon.microprofile.tyrus.HelidonComponentProvider; + provides jakarta.enterprise.inject.spi.Extension + with io.helidon.microprofile.tyrus.TyrusCdiExtension; + provides org.glassfish.tyrus.core.ComponentProvider + with io.helidon.microprofile.tyrus.HelidonComponentProvider; + provides io.helidon.nima.webserver.http1.spi.Http1UpgradeProvider + with io.helidon.microprofile.tyrus.TyrusUpgradeProvider; } diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoClient.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoClient.java index c7ad595a791..4c7373c3430 100644 --- a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoClient.java +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoClient.java @@ -92,7 +92,7 @@ public void onMessage(String message) { LOGGER.info("Client OnMessage called '" + message + "'"); int index = messages.length - (int) messageLatch.getCount(); - assertTrue(equals.apply(messages[index], message), messages[index] +":"+message); + assertTrue(equals.apply(messages[index], message), messages[index] + ":" + message); messageLatch.countDown(); if (messageLatch.getCount() == 0) { diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpoint.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpoint.java new file mode 100644 index 00000000000..8a47985519d --- /dev/null +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpoint.java @@ -0,0 +1,52 @@ +/* + * 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.microprofile.tyrus; + +import java.util.logging.Logger; + +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; + +@ServerEndpoint("/echoAnnot") +public class EchoEndpoint { + private static final Logger LOGGER = Logger.getLogger(EchoEndpoint.class.getName()); + + @OnOpen + public void onOpen(Session session) { + LOGGER.info("OnOpen called"); + } + + @OnMessage + public void echo(Session session, String message) throws Exception { + LOGGER.info("OnMessage called '" + message + "'"); + session.getBasicRemote().sendObject(message); + } + + @OnError + public void onError(Throwable t, Session session) { + LOGGER.info("OnError called"); + } + + @OnClose + public void onClose(Session session) { + LOGGER.info("OnClose called"); + } +} diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointBaseTest.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointBaseTest.java new file mode 100644 index 00000000000..1fa745ba0f7 --- /dev/null +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointBaseTest.java @@ -0,0 +1,54 @@ +/* + * 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.microprofile.tyrus; + +import java.net.http.HttpClient; +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import jakarta.inject.Inject; +import jakarta.ws.rs.client.WebTarget; + +class EchoEndpointBaseTest { + protected static final int WAIT_MILLIS = 5000; + protected static final String HELLO_WORLD = "Hello World"; + + @Inject + private WebTarget webTarget; + + private final HttpClient client; + + EchoEndpointBaseTest() { + client = HttpClient.newBuilder() + .connectTimeout(Duration.ofMillis(WAIT_MILLIS)) + .build(); + } + + protected HttpClient httpClient() { + return client; + } + + protected String serverPort() { + String uri = webTarget.getUri().toString(); + return uri.substring(uri.lastIndexOf(':') + 1); + } + + protected void await(CompletableFuture future) throws Exception { + future.get(WAIT_MILLIS, TimeUnit.MILLISECONDS); + } +} diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointProg.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointProg.java new file mode 100644 index 00000000000..8431693c969 --- /dev/null +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointProg.java @@ -0,0 +1,58 @@ +/* + * 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.microprofile.tyrus; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.websocket.CloseReason; +import jakarta.websocket.Endpoint; +import jakarta.websocket.EndpointConfig; +import jakarta.websocket.MessageHandler; +import jakarta.websocket.Session; + +public class EchoEndpointProg extends Endpoint { + private static final Logger LOGGER = Logger.getLogger(EchoEndpointProg.class.getName()); + + @Override + public void onOpen(Session session, EndpointConfig endpointConfig) { + LOGGER.info("OnOpen called"); + session.addMessageHandler(new MessageHandler.Whole() { + @Override + public void onMessage(String message) { + LOGGER.info("OnMessage called '" + message + "'"); + try { + session.getBasicRemote().sendObject(message); + } catch (Exception e) { + LOGGER.info(e.getMessage()); + } + } + }); + } + + @Override + public void onError(Session session, Throwable thr) { + LOGGER.log(Level.SEVERE, "OnError called", thr); + super.onError(session, thr); + } + + @Override + public void onClose(Session session, CloseReason closeReason) { + LOGGER.info("OnClose called"); + super.onClose(session, closeReason); + } +} diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketEndpointAppTest.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointProgTest.java similarity index 61% rename from microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketEndpointAppTest.java rename to microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointProgTest.java index fcf53070ebe..defcc10a3b6 100644 --- a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketEndpointAppTest.java +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointProgTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. + * 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. @@ -19,41 +19,39 @@ import java.net.URI; import java.util.Collections; import java.util.Set; +import java.util.concurrent.TimeUnit; import io.helidon.microprofile.server.RoutingPath; +import io.helidon.microprofile.tests.junit5.AddBean; +import io.helidon.microprofile.tests.junit5.HelidonTest; +import io.helidon.nima.websocket.CloseCodes; import jakarta.enterprise.context.Dependent; -import jakarta.enterprise.inject.se.SeContainerInitializer; import jakarta.websocket.Endpoint; import jakarta.websocket.server.ServerApplicationConfig; import jakarta.websocket.server.ServerEndpointConfig; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -/** - * A test that uses an {@code EndpointApplication} subclass annotated with - * {@code @RoutingPath} to register Websocket endpoints. The context for - * Websocket endpoints is defined by the value of {@code @RoutingPath}. - */ -public class WebSocketEndpointAppTest extends WebSocketBaseTest { +import org.junit.jupiter.api.Test; - @BeforeAll - static void initClass() { - container = SeContainerInitializer.newInstance() - .addBeanClasses(EndpointApplication.class) - .initialize(); - } +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; - @Override - public String context() { - return "/web"; - } +@HelidonTest +@AddBean(EchoEndpointProg.class) +@AddBean(EchoEndpointProgTest.EndpointApplication.class) +class EchoEndpointProgTest extends EchoEndpointBaseTest { @Test public void testEchoProg() throws Exception { - URI echoUri = URI.create("ws://localhost:" + port() + context() + "/echoProg"); - EchoClient echoClient = new EchoClient(echoUri); - echoClient.echo("hi", "how are you?"); + EchoListener listener = new EchoListener(); + URI echoUri = URI.create("ws://localhost:" + serverPort() + "/web/echoProg"); + java.net.http.WebSocket ws = httpClient().newWebSocketBuilder() + .buildAsync(echoUri, listener) + .get(WAIT_MILLIS, TimeUnit.SECONDS); + + await(ws.sendText(HELLO_WORLD, true)); + assertThat(listener.awaitEcho(), is(HELLO_WORLD)); + ws.sendClose(CloseCodes.NORMAL_CLOSE, "normal").get(); } @Dependent @@ -68,7 +66,7 @@ public Set getEndpointConfigs(Set> getAnnotatedEndpointClasses(Set> endpoints) { - return Collections.singleton(EchoEndpointAnnot.class); + return Collections.emptySet(); } } } diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketRestEndpointTest.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointRestTest.java similarity index 62% rename from microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketRestEndpointTest.java rename to microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointRestTest.java index 0927cfcfc16..e26ee29b930 100644 --- a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketRestEndpointTest.java +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointRestTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. + * 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. @@ -16,51 +16,48 @@ package io.helidon.microprofile.tyrus; -import jakarta.enterprise.inject.se.SeContainerInitializer; +import java.net.URI; + +import io.helidon.microprofile.tests.junit5.AddBean; +import io.helidon.microprofile.tests.junit5.HelidonTest; + import jakarta.ws.rs.Consumes; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; + import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static jakarta.ws.rs.client.Entity.text; import static org.hamcrest.CoreMatchers.is; -/** - * A test that mixes Websocket endpoints and REST resources in the same - * application. - */ -public class WebSocketRestEndpointTest extends WebSocketBaseTest { - - private static Client client; - - @BeforeAll - static void initClass() { - client = ClientBuilder.newClient(); - container = SeContainerInitializer.newInstance() - .addBeanClasses(EchoEndpointAnnot.class, EchoResource.class) - .initialize(); - } - - @Override - public String context() { - return ""; - } +@HelidonTest +@AddBean(EchoEndpoint.class) +@AddBean(EchoEndpointRestTest.EchoResource.class) +class EchoEndpointRestTest extends EchoEndpointBaseTest { @Test - public void testEchoRest() { - String echo = client.target("http://localhost:" + port() + "/echoRest") + public void testEchoRest() throws Exception { + // Test REST endpoint + String restUri = "http://localhost:" + serverPort() + "/echoRest"; + Client restClient = ClientBuilder.newClient(); + String echo = restClient.target(restUri) .request("text/plain") .post(text("echo"), String.class); MatcherAssert.assertThat(echo, is("echo")); + + // Test WS endpoint + String echoUri = "ws://localhost:" + serverPort() + "/echoAnnot"; + EchoClient echoClient = new EchoClient(URI.create(echoUri)); + echoClient.echo("hi", "how are you?"); } @Path("/echoRest") public static class EchoResource { + @POST @Produces("text/plain") @Consumes("text/plain") diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointTest.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointTest.java new file mode 100644 index 00000000000..efb31ae0eb9 --- /dev/null +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoEndpointTest.java @@ -0,0 +1,47 @@ +/* + * 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.microprofile.tyrus; + +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import io.helidon.microprofile.tests.junit5.AddBean; +import io.helidon.microprofile.tests.junit5.HelidonTest; +import io.helidon.nima.websocket.CloseCodes; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@HelidonTest +@AddBean(EchoEndpoint.class) +class EchoEndpointTest extends EchoEndpointBaseTest { + + @Test + public void testEchoAnnot() throws Exception { + EchoListener listener = new EchoListener(); + URI echoUri = URI.create("ws://localhost:" + serverPort() + "/echoAnnot"); + java.net.http.WebSocket ws = httpClient().newWebSocketBuilder() + .buildAsync(echoUri, listener) + .get(WAIT_MILLIS, TimeUnit.SECONDS); + + await(ws.sendText(HELLO_WORLD, true)); + assertThat(listener.awaitEcho(), is(HELLO_WORLD)); + ws.sendClose(CloseCodes.NORMAL_CLOSE, "normal").get(); + } +} diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoListener.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoListener.java new file mode 100644 index 00000000000..8644c66333c --- /dev/null +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/EchoListener.java @@ -0,0 +1,45 @@ +/* + * 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.microprofile.tyrus; + +import java.net.http.WebSocket; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; + +class EchoListener implements WebSocket.Listener { + private static final int WAIT_MILLIS = 5000; + private static final int INVOCATION_COUNTER = 10; + + private final CompletableFuture echoFuture = new CompletableFuture<>(); + + @Override + public void onOpen(java.net.http.WebSocket webSocket) { + webSocket.request(INVOCATION_COUNTER); + } + + @Override + public CompletionStage onText(java.net.http.WebSocket webSocket, CharSequence data, boolean last) { + echoFuture.complete(String.valueOf(data)); + return null; + } + + String awaitEcho() throws Exception { + return echoFuture.get(WAIT_MILLIS, TimeUnit.MILLISECONDS); + } +} + diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketExtensionEndpointTest.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/ExtensionEndpointTest.java similarity index 61% rename from microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketExtensionEndpointTest.java rename to microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/ExtensionEndpointTest.java index 0e31be91347..9eb5ba650eb 100644 --- a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketExtensionEndpointTest.java +++ b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/ExtensionEndpointTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. + * 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. @@ -21,53 +21,29 @@ import java.util.List; import java.util.logging.Logger; -import io.helidon.microprofile.server.ServerCdiExtension; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.se.SeContainerInitializer; -import jakarta.enterprise.inject.spi.CDI; +import io.helidon.microprofile.tests.junit5.AddBean; +import io.helidon.microprofile.tests.junit5.HelidonTest; import jakarta.websocket.Extension; import jakarta.websocket.OnMessage; import jakarta.websocket.Session; import jakarta.websocket.server.ServerEndpoint; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -/** - * A test that mixes Websocket endpoints and extensions in the same application. - */ -public class WebSocketExtensionEndpointTest { - - static SeContainer container; - - @BeforeAll - static void initClass() { - container = SeContainerInitializer.newInstance() - .addBeanClasses(ExtensionEndpointAnnot.class, TestExtension.class) - .initialize(); - } - - @AfterAll - static void destroyClass() { - container.close(); - } - - public int port() { - ServerCdiExtension cdiExtension = CDI.current().getBeanManager().getExtension(ServerCdiExtension.class); - return cdiExtension.port(); - } +@HelidonTest +@AddBean(ExtensionEndpointTest.TestExtension.class) +@AddBean(ExtensionEndpointTest.ExtensionEndpoint.class) +class ExtensionEndpointTest extends EchoEndpointBaseTest { @Test public void test() throws Exception { - URI echoUri = URI.create("ws://localhost:" + port() + "/extAnnot"); + URI echoUri = URI.create("ws://localhost:" + serverPort() + "/extAnnot"); EchoClient echoClient = new EchoClient(echoUri, new TestExtension()); echoClient.echo("hi", "how are you?"); } @ServerEndpoint("/extAnnot") - public static class ExtensionEndpointAnnot { - private static final Logger LOGGER = Logger.getLogger(ExtensionEndpointAnnot.class.getName()); + public static class ExtensionEndpoint { + private static final Logger LOGGER = Logger.getLogger(ExtensionEndpoint.class.getName()); @OnMessage public void echo(Session session, String message) throws Exception { diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketBaseTest.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketBaseTest.java deleted file mode 100644 index 5e39c892755..00000000000 --- a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketBaseTest.java +++ /dev/null @@ -1,145 +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.tyrus; - -import java.io.IOException; -import java.net.URI; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.microprofile.server.ServerCdiExtension; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.spi.CDI; -import jakarta.websocket.CloseReason; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.MessageHandler; -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; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.RepeatedTest; -import org.junit.jupiter.api.Test; - -/** - * Class WebSocketBaseTest. - */ -public abstract class WebSocketBaseTest { - - static SeContainer container; - - @AfterAll - static void destroyClass() { - container.close(); - } - - public abstract String context(); - - public int port() { - ServerCdiExtension cdiExtension = CDI.current().getBeanManager().getExtension(ServerCdiExtension.class); - return cdiExtension.port(); - } - - @Test - public void testEchoAnnot() throws Exception { - URI echoUri = URI.create("ws://localhost:" + port() + context() + "/echoAnnot"); - EchoClient echoClient = new EchoClient(echoUri); - echoClient.echo("hi", "how are you?"); - echoClient.shutdown(); - } - - @ServerEndpoint("/echoAnnot") - public static class EchoEndpointAnnot { - private static final Logger LOGGER = Logger.getLogger(EchoEndpointAnnot.class.getName()); - - @OnOpen - public void onOpen(Session session) throws IOException { - LOGGER.info("OnOpen called"); - verifyRunningThread(session, LOGGER); - } - - @OnMessage - public void echo(Session session, String message) throws Exception { - LOGGER.info("OnMessage called '" + message + "'"); - session.getBasicRemote().sendObject(message); - verifyRunningThread(session, LOGGER); - } - - @OnError - public void onError(Throwable t, Session session) throws IOException { - LOGGER.info("OnError called"); - verifyRunningThread(session, LOGGER); - } - - @OnClose - public void onClose(Session session) throws IOException { - LOGGER.info("OnClose called"); - verifyRunningThread(session, LOGGER); - } - } - - public static class EchoEndpointProg extends Endpoint { - private static final Logger LOGGER = Logger.getLogger(EchoEndpointProg.class.getName()); - - @Override - public void onOpen(Session session, EndpointConfig endpointConfig) { - LOGGER.info("OnOpen called"); - session.addMessageHandler(new MessageHandler.Whole() { - @Override - public void onMessage(String message) { - LOGGER.info("OnMessage called '" + message + "'"); - try { - session.getBasicRemote().sendObject(message); - } catch (Exception e) { - LOGGER.info(e.getMessage()); - } - } - }); - } - - @Override - public void onError(Session session, Throwable thr) { - LOGGER.log(Level.SEVERE, "OnError called", thr); - super.onError(session, thr); - } - - @Override - public void onClose(Session session, CloseReason closeReason) { - LOGGER.info("OnClose called"); - super.onClose(session, closeReason); - } - } - - /** - * Verify that endpoint methods are running in a Helidon thread pool. - * - * @param session Websocket session. - * @param logger A logger. - * @throws IOException Exception during close. - */ - private static void verifyRunningThread(Session session, Logger logger) throws IOException { - Thread thread = Thread.currentThread(); - if (!thread.getName().contains("helidon")) { - logger.warning("Websocket handler running in incorrect thread " + thread); - session.close(); - } - } -} diff --git a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketEndpointTest.java b/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketEndpointTest.java deleted file mode 100644 index e0b7fec45d2..00000000000 --- a/microprofile/websocket/src/test/java/io/helidon/microprofile/tyrus/WebSocketEndpointTest.java +++ /dev/null @@ -1,39 +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.tyrus; - -import jakarta.enterprise.inject.se.SeContainerInitializer; -import org.junit.jupiter.api.BeforeAll; - -/** - * A test that registers a single annotated endpoint on the default WebSocket - * context. See {@code WebSocketCdiExtension#DEFAULT_WEBSOCKET_PATH}. - */ -public class WebSocketEndpointTest extends WebSocketBaseTest { - - @BeforeAll - static void initClass() { - container = SeContainerInitializer.newInstance() - .addBeanClasses(EchoEndpointAnnot.class) - .initialize(); - } - - @Override - public String context() { - return ""; - } -} diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConnectionProvider.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConnectionProvider.java index 09df5c8d813..2a8deb27523 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConnectionProvider.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConnectionProvider.java @@ -251,8 +251,8 @@ Map upgradeProviders() { List providers = upgradeProviders.build().asList(); Map providerMap = new HashMap<>(); - for (Http1UpgradeProvider upgradeProvider : providers) { - providerMap.put(upgradeProvider.supportedProtocol(), upgradeProvider); + for (Http1UpgradeProvider upgradeProvider : providers) { // sorted by weight + providerMap.putIfAbsent(upgradeProvider.supportedProtocol(), upgradeProvider); } return Map.copyOf(providerMap); } diff --git a/nima/websocket/webserver/src/main/java/io/helidon/nima/websocket/webserver/WsUpgradeProvider.java b/nima/websocket/webserver/src/main/java/io/helidon/nima/websocket/webserver/WsUpgradeProvider.java index a4df081076d..14c2ffcb6a4 100644 --- a/nima/websocket/webserver/src/main/java/io/helidon/nima/websocket/webserver/WsUpgradeProvider.java +++ b/nima/websocket/webserver/src/main/java/io/helidon/nima/websocket/webserver/WsUpgradeProvider.java @@ -41,21 +41,50 @@ * {@link java.util.ServiceLoader} provider implementation for upgrade from HTTP/1.1 to WebSocket. */ public class WsUpgradeProvider implements Http1UpgradeProvider { + + /** + * Websocket key header name. + */ + protected static final HeaderName WS_KEY = Header.create("Sec-WebSocket-Key"); + + /** + * Websocket version header name. + */ + protected static final HeaderName WS_VERSION = Header.create("Sec-WebSocket-Version"); + + /** + * Websocket protocol header name. + */ + protected static final HeaderName PROTOCOL = Header.create("Sec-WebSocket-Protocol"); + + /** + * Switching response prefix. + */ + protected static final String SWITCHING_PROTOCOL_PREFIX = "HTTP/1.1 101 Switching Protocols\r\n" + + "Connection: Upgrade\r\n" + + "Upgrade: websocket\r\n" + + "Sec-WebSocket-Accept: "; + + /** + * Switching response suffix. + */ + protected static final String SWITCHING_PROTOCOLS_SUFFIX = "\r\n\r\n"; + + /** + * Supported version. + */ + protected static final String SUPPORTED_VERSION = "13"; + + /** + * Supported version header. + */ + protected static final Http.HeaderValue SUPPORTED_VERSION_HEADER = Header.create(WS_VERSION, SUPPORTED_VERSION); + private static final System.Logger LOGGER = System.getLogger(WsUpgradeProvider.class.getName()); - private static final HeaderName WS_KEY = Header.create("Sec-WebSocket-Key"); - private static final HeaderName WS_VERSION = Header.create("Sec-WebSocket-Version"); - private static final HeaderName PROTOCOL = Header.create("Sec-WebSocket-Protocol"); private static final byte[] KEY_SUFFIX = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(StandardCharsets.US_ASCII); private static final int KEY_SUFFIX_LENGTH = KEY_SUFFIX.length; private static final Base64.Decoder B64_DECODER = Base64.getDecoder(); private static final Base64.Encoder B64_ENCODER = Base64.getEncoder(); - private static final String SWITCHING_PROTOCOL_PREFIX = "HTTP/1.1 101 Switching Protocols\r\n" - + "Connection: Upgrade\r\n" - + "Upgrade: websocket\r\n" - + "Sec-WebSocket-Accept: "; - private static final String SWITCHING_PROTOCOLS_SUFFIX = "\r\n\r\n"; - private static final String SUPPORTED_VERSION = "13"; - private static final Http.HeaderValue SUPPORTED_VERSION_HEADER = Header.create(WS_VERSION, SUPPORTED_VERSION); private final Set origins; private final boolean anyOrigin; @@ -119,10 +148,10 @@ public ServerConnection upgrade(ConnectionContext ctx, HttpPrologue prologue, Wr return null; } - if (!anyOrigin) { + if (!anyOrigin()) { if (headers.contains(Header.ORIGIN)) { String origin = headers.get(Header.ORIGIN).value(); - if (!origins.contains(origin)) { + if (!origins().contains(origin)) { throw RequestException.builder() .message("Invalid Origin") .type(DirectHandler.EventType.FORBIDDEN) @@ -144,7 +173,15 @@ public ServerConnection upgrade(ConnectionContext ctx, HttpPrologue prologue, Wr return new WsConnection(ctx, prologue, headers, wsKey, route); } - private String hash(ConnectionContext ctx, String wsKey) { + protected boolean anyOrigin() { + return anyOrigin; + } + + protected Set origins() { + return origins; + } + + protected String hash(ConnectionContext ctx, String wsKey) { byte[] decodedBytes = B64_DECODER.decode(wsKey); if (decodedBytes.length != 16) { // this is required by the specification (RFC-6455) From 2a83a850a4d2bba36caeee3eae5aab26903bb239 Mon Sep 17 00:00:00 2001 From: Daniel Kec Date: Mon, 28 Nov 2022 16:50:04 +0100 Subject: [PATCH 17/36] Bump-up reactive messaging/ops to 3.0 (#5526) Signed-off-by: Daniel Kec --- dependencies/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 8b14ce5825a..86499d9a29f 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -109,9 +109,9 @@ 2.0 4.0 3.0 - 3.0-RC3 - 3.0-RC1 - 3.0-RC1 + 3.0 + 3.0 + 3.0 3.0 3.0 2.0-RC1 From 3cfb5c9fa105f82c32883b9992e4265d5392990a Mon Sep 17 00:00:00 2001 From: Daniel Kec Date: Mon, 28 Nov 2022 16:52:45 +0100 Subject: [PATCH 18/36] 5469 - forEachCS (#5532) Signed-off-by: Daniel Kec --- .../io/helidon/common/reactive/Multi.java | 18 ++++++- .../io/helidon/common/reactive/MultiTest.java | 47 ++++++++++++++++++- docs/includes/reactivestreams/engine.adoc | 3 +- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/common/reactive/src/main/java/io/helidon/common/reactive/Multi.java b/common/reactive/src/main/java/io/helidon/common/reactive/Multi.java index dd96b82970b..b3be57e450d 100644 --- a/common/reactive/src/main/java/io/helidon/common/reactive/Multi.java +++ b/common/reactive/src/main/java/io/helidon/common/reactive/Multi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * 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. @@ -1111,7 +1111,7 @@ default U to(Function, ? extends U> converter) { // -------------------------------------------------------------------------------------------------------- /** - * Terminal stage, invokes provided consumer for every item in the stream. + * Terminal stage, invokes provided consumer for every item in the stream with no backpressure. * * @param consumer consumer to be invoked for each item * @return Single completed when the stream terminates @@ -1132,6 +1132,20 @@ default Single forEach(Consumer consumer) { return single; } + /** + * Terminal stage, invokes provided consumer for every item in the stream with strict backpressure. + * Items are requested 1 by 1 with no prefetch always waiting for each completion stage + * to complete before requesting another item. + * + * @param function invoked for each item returning completion stage to signal asynchronous completion + * @return Single completed when the stream terminates + */ + default Single forEachCompletionStage(Function> function) { + return map(function::apply) + .flatMap(cs -> Single.create(cs, true), 1, false, 1) + .ignoreElements(); + } + /** * Terminal stage, ignore all items and complete returned {@code Single} successfully or exceptionally. * diff --git a/common/reactive/src/test/java/io/helidon/common/reactive/MultiTest.java b/common/reactive/src/test/java/io/helidon/common/reactive/MultiTest.java index 90134de00c4..b5adfd71c83 100644 --- a/common/reactive/src/test/java/io/helidon/common/reactive/MultiTest.java +++ b/common/reactive/src/test/java/io/helidon/common/reactive/MultiTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 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. @@ -15,12 +15,15 @@ */ package io.helidon.common.reactive; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscription; import java.util.concurrent.TimeUnit; @@ -31,7 +34,9 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.equalTo; @@ -42,6 +47,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.empty; /** @@ -49,6 +55,21 @@ */ public class MultiTest { + private static ExecutorService exec; + + @BeforeAll + static void beforeAll() { + exec = Executors.newFixedThreadPool(4); + } + + @AfterAll + static void afterAll() throws InterruptedException { + exec.shutdown(); + if (!exec.awaitTermination(5, TimeUnit.SECONDS)) { + exec.shutdownNow(); + } + } + @Test public void testJust() { MultiTestSubscriber subscriber = new MultiTestSubscriber<>(); @@ -671,6 +692,30 @@ public void testDoubleSubscribe() { assertThat(subscriber2.getLastError(), is(nullValue())); } + @Test + void testForEachCompletionStage() { + List flags = Collections.synchronizedList(new ArrayList<>(8)); + Multi.just(200, 150, 100, 50) + .log() + .forEachCompletionStage(i -> CompletableFuture.runAsync(() -> { + flags.add("entering " + i); + try { + Thread.sleep(i); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + flags.add("leaving " + i); + }, exec)) + .await(); + + assertThat(flags, contains( + "entering 200", "leaving 200", + "entering 150", "leaving 150", + "entering 100", "leaving 100", + "entering 50", "leaving 50" + )); + } + private static class MultiTestSubscriber extends TestSubscriber { @Override diff --git a/docs/includes/reactivestreams/engine.adoc b/docs/includes/reactivestreams/engine.adoc index 9e1d81f2158..5d4d69031a3 100644 --- a/docs/includes/reactivestreams/engine.adoc +++ b/docs/includes/reactivestreams/engine.adoc @@ -96,7 +96,8 @@ Single.just("1") |flatMapOptional|Transform each upstream item with the supplied function and flatten the resulting `Optional` to the downstream as item if present. |observeOn|Re-emit the upstream's signals to the downstream on the given executor's thread using a default buffer size of 32 and errors skipping ahead of items. |observeOn|Re-emit the upstream's signals to the downstream on the given executor's thread. -|forEach|Terminal stage, invokes provided consumer for every item in the stream. +|forEach|Terminal stage, invokes provided consumer for every item in the stream with no backpressure. +|forEachCompletionStage|Terminal stage, invokes provided function for every item in the stream with strict backpressure, requests another item only when previous operation is finished. |collectList|Collect the items of this `Multi` instance into a `Single` of `List`. |collect|Collect the items of this `Multi` instance into a `Single`. |collect|Collect the items of this `Multi` into a collection provided via a `Supplier` and mutated by a `BiConsumer` callback. From 1e6a678d34731b1337162dad8a948008853622c1 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Mon, 28 Nov 2022 21:02:24 +0100 Subject: [PATCH 19/36] Fixed OpentraceableClientE2ETest to be more deterministic (#5536) * Fixed OpentraceableClientE2ETest to be more deterministic (and added explanation of what it should test) Disabled BulkheadTest that is failing intermittently * Fixed tests that leave current span scope open (and influence other tests) --- .../nima/faulttolerance/BulkheadTest.java | 11 +- .../reactive/webserver/WebTracingConfig.java | 4 +- .../jersey/client/ClientTracingFilter.java | 14 - .../tests/it1/OpentraceableClientE2ETest.java | 244 +++++++++++------- .../it1/OpentraceableClientFilterTest.java | 142 ++++++---- .../io/helidon/tracing/zipkin/ZipkinSpan.java | 18 +- .../tracing/zipkin/ZipkinSpanBuilder.java | 15 +- 7 files changed, 279 insertions(+), 169 deletions(-) diff --git a/nima/fault-tolerance/src/test/java/io/helidon/nima/faulttolerance/BulkheadTest.java b/nima/fault-tolerance/src/test/java/io/helidon/nima/faulttolerance/BulkheadTest.java index c2895dfedda..d2aac3bd65a 100644 --- a/nima/fault-tolerance/src/test/java/io/helidon/nima/faulttolerance/BulkheadTest.java +++ b/nima/fault-tolerance/src/test/java/io/helidon/nima/faulttolerance/BulkheadTest.java @@ -25,6 +25,8 @@ import io.helidon.logging.common.LogConfig; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import static java.lang.System.Logger.Level.INFO; @@ -42,14 +44,19 @@ class BulkheadTest { private static final long WAIT_TIMEOUT_MILLIS = 10000; - private final CountDownLatch enqueuedSubmitted = new CountDownLatch(1); + private CountDownLatch enqueuedSubmitted; @BeforeAll static void setupTest() { LogConfig.configureRuntime(); } - @Test + @BeforeEach + void resetLatch() { + enqueuedSubmitted = new CountDownLatch(1); + } + + @Disabled void testBulkhead() throws InterruptedException, ExecutionException, java.util.concurrent.TimeoutException { // Create bulkhead of 1 with queue length 1 String name = "unit:testBulkhead"; diff --git a/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/WebTracingConfig.java b/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/WebTracingConfig.java index 0f7ef35d18f..accc8fc090d 100644 --- a/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/WebTracingConfig.java +++ b/reactive/webserver/webserver/src/main/java/io/helidon/reactive/webserver/WebTracingConfig.java @@ -303,13 +303,13 @@ private void doAccept(ServerRequest req, ServerResponse res) { String spanName = spanConfig.newName().orElse(TRACING_SPAN_HTTP_REQUEST); if (spanName.indexOf('%') > -1) { - spanName = String.format(spanName, req.method().name(), req.path(), req.query()); + spanName = String.format(spanName, req.method().text(), req.path(), req.query()); } // tracing is enabled, so we replace the parent span with web server parent span Span.Builder spanBuilder = tracer.spanBuilder(spanName) .kind(Span.Kind.SERVER) .tag(Tag.COMPONENT.create("helidon-reactive-webserver")) - .tag(Tag.HTTP_METHOD.create(req.method().name())) + .tag(Tag.HTTP_METHOD.create(req.method().text())) .tag(Tag.HTTP_URL.create(req.uri().toString())) .tag(Tag.HTTP_VERSION.create(req.version().value())); diff --git a/tracing/jersey-client/src/main/java/io/helidon/tracing/jersey/client/ClientTracingFilter.java b/tracing/jersey-client/src/main/java/io/helidon/tracing/jersey/client/ClientTracingFilter.java index be6a308e1f3..fdf4086a737 100644 --- a/tracing/jersey-client/src/main/java/io/helidon/tracing/jersey/client/ClientTracingFilter.java +++ b/tracing/jersey-client/src/main/java/io/helidon/tracing/jersey/client/ClientTracingFilter.java @@ -18,13 +18,10 @@ import java.net.URI; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.ServiceLoader; -import io.helidon.common.HelidonServiceLoader; import io.helidon.common.context.Contexts; import io.helidon.tracing.HeaderConsumer; import io.helidon.tracing.HeaderProvider; @@ -36,7 +33,6 @@ import io.helidon.tracing.config.SpanTracingConfig; import io.helidon.tracing.config.TracingConfigUtil; import io.helidon.tracing.jersey.client.internal.TracingContext; -import io.helidon.tracing.spi.TracerProvider; import jakarta.annotation.Priority; import jakarta.ws.rs.Priorities; @@ -138,22 +134,12 @@ public class ClientTracingFilter implements ClientRequestFilter, ClientResponseF private static final int HTTP_STATUS_ERROR_THRESHOLD = 400; private static final int HTTP_STATUS_SERVER_ERROR_THRESHOLD = 500; - private final Optional tracerProvider; - /** * Default constructor so this filter can be registered with Jersey * as a class. * Required by integrated platform. */ public ClientTracingFilter() { - Iterator iterator = HelidonServiceLoader.create(ServiceLoader.load(TracerProvider.class)) - .iterator(); - - if (iterator.hasNext()) { - tracerProvider = Optional.of(iterator.next()); - } else { - tracerProvider = Optional.empty(); - } } @Override diff --git a/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientE2ETest.java b/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientE2ETest.java index 707e6f5ad6c..425bfa19d9d 100644 --- a/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientE2ETest.java +++ b/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientE2ETest.java @@ -18,10 +18,12 @@ import java.lang.System.Logger; import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -48,26 +50,35 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.fail; -/** - * The ZipkinClientTest. +/* + * What do we expect to get: + * 1. Client creates a "client-call" new trace - top level span (parent is null) - in this test + * 2. Client creates a "get" request span - parent is (1.), same trace ID - client filter + * 3. Server creates a "http request" span - parent is (1.), same trace ID - server + * (I thought parent should be 2, but this is how brave tracer injects/extracts the headers) + * 4. Server creates a "content-write" span - parent is (3.), same trace ID - server + * */ class OpentraceableClientE2ETest { - - private static final int EXPECTED_TRACE_EVENTS_COUNT = 5; - private static final int EXPECTED_DISTINCT_SPAN_COUNT = 4; // a span is reported twice, once by each of the two tracers - + /** + * We expect two client spans and two server spans. + */ + private static final int EXPECTED_TRACE_EVENTS_COUNT = 4; private static final Logger LOGGER = System.getLogger(OpentraceableClientE2ETest.class.getName()); private static final Logger.Level LEVEL = Logger.Level.DEBUG; - private static final boolean IS_LOGGABLE = LOGGER.isLoggable(LEVEL); - private static final CountDownLatch EVENTS_LATCH = new CountDownLatch(EXPECTED_TRACE_EVENTS_COUNT); + private static final List CLIENT_SPANS = Collections.synchronizedList(new ArrayList<>()); + private static final List SERVER_SPANS = Collections.synchronizedList(new ArrayList<>()); + private static final Duration TIMEOUT = Duration.ofSeconds(10); - private static final Map EVENTS_MAP = new ConcurrentHashMap<>(); private static WebServer server; private static Client client; + private static CountDownLatch eventsLatch; @BeforeAll static void startServerInitClient() { @@ -76,11 +87,9 @@ static void startServerInitClient() { } @AfterAll - static void stopAndClose() throws Exception { + static void stopAndClose() { if (server != null) { - server.shutdown() - .toCompletableFuture() - .get(10, TimeUnit.SECONDS); + server.shutdown().await(TIMEOUT); } if (client != null) { @@ -90,71 +99,155 @@ static void stopAndClose() throws Exception { @BeforeEach void resetTraces() { - EVENTS_MAP.clear(); + CLIENT_SPANS.clear(); + SERVER_SPANS.clear(); + eventsLatch = new CountDownLatch(EXPECTED_TRACE_EVENTS_COUNT); } @Test void e2e() throws Exception { io.helidon.tracing.Tracer tracer = tracer("test-client"); - Span start = tracer.spanBuilder("client-call") + Span clientSpan = tracer.spanBuilder("client-call") + .kind(Span.Kind.CLIENT) .start(); Response response = client.target("http://localhost:" + server.port()) .property(ClientTracingFilter.TRACER_PROPERTY_NAME, tracer) - .property(ClientTracingFilter.CURRENT_SPAN_CONTEXT_PROPERTY_NAME, start.context()) + .property(ClientTracingFilter.CURRENT_SPAN_CONTEXT_PROPERTY_NAME, clientSpan.context()) .request() .get(); assertThat(response.getStatus(), is(200)); - start.end(); + clientSpan.end(); - if (!EVENTS_LATCH.await(10, TimeUnit.SECONDS)) { + if (!eventsLatch.await(10, TimeUnit.SECONDS)) { fail("Timed out waiting to detect expected " + EXPECTED_TRACE_EVENTS_COUNT + "; remaining latch count: " - + EVENTS_LATCH.getCount()); + + eventsLatch.getCount()); } - assertThat("Spans reported", EVENTS_MAP.entrySet(), hasSize(EXPECTED_DISTINCT_SPAN_COUNT)); + assertThat("Client spans reported. Client: " + printSpans(CLIENT_SPANS) + ", Server: " + printSpans(SERVER_SPANS), + CLIENT_SPANS, + hasSize(2)); + assertThat("Server spans reported. Client: " + printSpans(CLIENT_SPANS) + ", Server: " + printSpans(SERVER_SPANS), + SERVER_SPANS, + hasSize(2)); + + TraceContext traceContext = ((BraveSpanContext) clientSpan.unwrap(io.opentracing.Span.class).context()).unwrap(); + + /* + Validate client spans + "client-call" - our explicit span with no parent + "get" - client GET request, has "client-call" as parent + */ + var spansByName = spansByName(CLIENT_SPANS); + var spansById = spansById(CLIENT_SPANS); + + // top level client span + zipkin2.Span clientTopLevelSpan = spansById.get(traceContext.spanIdString()); + assertThat("Manual client span with id " + traceContext.spanIdString() + " was not found in " + + printSpans(spansById), clientTopLevelSpan, notNullValue()); + assertAll("Manual client span", + () -> assertThat("Should not have a parent", clientTopLevelSpan.parentId(), nullValue()), + () -> assertThat("Correct name", clientTopLevelSpan.name(), is("client-call")), + () -> assertThat("Trace ID is not null", clientTopLevelSpan.traceId(), notNullValue()) + ); - TraceContext traceContext = ((BraveSpanContext) start.unwrap(io.opentracing.Span.class).context()).unwrap(); + String manualClientId = clientTopLevelSpan.id(); + String traceId = clientTopLevelSpan.traceId(); - zipkin2.Span reportedSpan = EVENTS_MAP.get(traceContext.spanIdString()); - assertThat("Explicitly-started span with id " + traceContext.spanIdString() + " was not found in " - + printSpans(EVENTS_MAP), reportedSpan, notNullValue()); - // Remove the reported span's parent, which was also reported, and start the ancestry check with it. - zipkin2.Span parentOfReportedSpan = EVENTS_MAP.remove(reportedSpan.parentId()); - assertThat("Parent of explicitly-started span (parent ID = " + reportedSpan.parentId() + ") absent from " - + printSpans(EVENTS_MAP), parentOfReportedSpan, notNullValue()); - if (IS_LOGGABLE) { - LOGGER.log(LEVEL, String.format("Starting ancestry check with span %s", parentOfReportedSpan.id())); + // JAR-RS client span + var clientJaxRsSpan = spansByName.get("get"); + assertThat("JAX-RS GET client span was not found in " + + printSpans(spansByName), clientJaxRsSpan, notNullValue()); + assertAll("JAX-RS GET client span", + () -> assertThat("Parent should be manual span", clientJaxRsSpan.parentId(), is(manualClientId)), + () -> assertThat("TraceID should be the same for all spans", clientJaxRsSpan.traceId(), is(traceId)), + () -> assertThat("Correct name", clientJaxRsSpan.name(), is("get")) + ); + + /* + Validate server spans + "http request" - top level WebServer span + "content-write" - WebServer span for writing entity + */ + spansByName = spansByName(SERVER_SPANS); + + // WebServer span + var serverRequestSpan = spansByName.get("http request"); + assertThat("Server \"http request\" span was not found in " + + printSpans(spansByName), serverRequestSpan, notNullValue()); + assertAll("Server \"http request\" span", + () -> assertThat("Parent should be manual span", serverRequestSpan.parentId(), is(manualClientId)), + () -> assertThat("TraceID should be the same for all spans", serverRequestSpan.traceId(), is(traceId)), + () -> assertThat("Correct name", serverRequestSpan.name(), is("http request")) + ); + + String serverRequestId = serverRequestSpan.id(); + + // WebServer span + var serverContentSpan = spansByName.get("content-write"); + assertThat("Server \"content-write\" span was not found in " + + printSpans(spansByName), serverContentSpan, notNullValue()); + assertAll("Server \"content-write\" span", + () -> assertThat("Parent should be server request span", serverContentSpan.parentId(), is(serverRequestId)), + () -> assertThat("TraceID should be the same for all spans", serverContentSpan.traceId(), is(traceId)), + () -> assertThat("Correct name", serverContentSpan.name(), is("content-write")) + ); + } + + private static Map spansByName(List spans) { + Map result = new HashMap<>(); + + for (zipkin2.Span span : spans) { + zipkin2.Span existing = result.putIfAbsent(span.name(), span); + assertThat("There should not be two spans named the same", existing, nullValue()); } - assertSpanChain(parentOfReportedSpan, EVENTS_MAP); - assertThat("Remaining EVENTS_MAP entries after ancestry check", EVENTS_MAP.entrySet(), hasSize(0)); + + return result; + } + + private static Map spansById(List spans) { + Map result = new HashMap<>(); + + for (zipkin2.Span span : spans) { + zipkin2.Span existing = result.putIfAbsent(span.id(), span); + assertThat("There should not be two spans with the same id", existing, nullValue()); + } + + return result; } /** - * Use custom {@link Tracer} that adds events to {@link #EVENTS_MAP} map. + * Use custom {@link Tracer} that adds events to {@link #CLIENT_SPANS} or {@link #SERVER_SPANS}. */ private static io.helidon.tracing.Tracer tracer(String serviceName) { Tracing braveTracing = Tracing.newBuilder() .localServiceName(serviceName) .spanReporter(span -> { - EVENTS_MAP.put(span.id(), span); - EVENTS_LATCH.countDown(); - if (IS_LOGGABLE) { + if (span.kind() == zipkin2.Span.Kind.CLIENT) { + CLIENT_SPANS.add(span); + } else { + SERVER_SPANS.add(span); + } + + eventsLatch.countDown(); + if (LOGGER.isLoggable(LEVEL)) { LOGGER.log(LEVEL, String.format( - """ - Service %10s recorded span %14s/%s, parent %s, trace %s; \ - map size: %d; remaining latch count: %d \ - """, - serviceName, - span.name(), - span.id(), - span.parentId(), - span.traceId(), - EVENTS_MAP.size(), - EVENTS_LATCH.getCount())); + """ + Service %10s recorded span %14s/%s, %s kind, parent %s, trace %s; \ + client map size: %d; server map size: %d; remaining latch count: %d \ + """, + serviceName, + span.name(), + span.id(), + span.kind(), + span.parentId(), + span.traceId(), + CLIENT_SPANS.size(), + SERVER_SPANS.size(), + eventsLatch.getCount())); } }) .build(); @@ -175,52 +268,21 @@ private static WebServer startWebServer() { } private String printSpans(Map spans) { + return printSpans(spans.values()); + } + + private String printSpans(Collection spans) { StringBuilder sb = new StringBuilder(); - for (Map.Entry span : spans.entrySet()) { - sb.append("id: ").append(span.getValue().id()).append("\n"); - sb.append("parent id: ").append(span.getValue().parentId()).append("\n"); - sb.append("trace id: ").append(span.getValue().traceId()).append("\n"); - sb.append("name: ").append(span.getValue().name()).append("\n"); - sb.append("local service: ").append(span.getValue().localServiceName()).append("\n"); - sb.append("remote service: ").append(span.getValue().remoteServiceName()).append("\n"); + for (zipkin2.Span span : spans) { + sb.append("id: ").append(span.id()).append("\n"); + sb.append("parent id: ").append(span.parentId()).append("\n"); + sb.append("trace id: ").append(span.traceId()).append("\n"); + sb.append("name: ").append(span.name()).append("\n"); + sb.append("local service: ").append(span.localServiceName()).append("\n"); + sb.append("remote service: ").append(span.remoteServiceName()).append("\n"); sb.append("=====\n"); } return sb.toString(); } - /** - * Assert that all the spans are in a strict {@code parent-child-grandchild-[grandgrandchild]-[...]} relationship. - */ - private void assertSpanChain(zipkin2.Span topSpan, Map spans) { - if (spans.isEmpty()) { - if (IS_LOGGABLE) { - LOGGER.log(LEVEL, String.format("Map is empty for checking descendants of %14s/%s", - topSpan.name(), - topSpan.id())); - } - // end the recursion - return; - } - if (IS_LOGGABLE) { - LOGGER.log(LEVEL, String.format("Attempting removal and checking descendants of %14s/%s", - topSpan.name(), - topSpan.id())); - } - Optional removeSpan = findAndRemoveSpan(topSpan.id(), spans); - assertSpanChain(removeSpan.orElseThrow( - () -> new AssertionError("Span with parent ID not found: " + topSpan.id() + " at: " + printSpans(spans))), - spans); - } - - private Optional findAndRemoveSpan(String id, Map spans) { - Optional span = spans.entrySet() - .stream() - .filter(entry -> id.equals(entry.getValue().parentId())) - .map(Map.Entry::getValue) - .findFirst(); - - span.ifPresent(span1 -> spans.remove(span1.id())); - return span; - } - } diff --git a/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientFilterTest.java b/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientFilterTest.java index 5ebc945894c..7e5c96677c2 100644 --- a/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientFilterTest.java +++ b/tracing/tests/it-tracing-client-zipkin/src/test/java/io/helidon/tracing/tests/it1/OpentraceableClientFilterTest.java @@ -17,9 +17,14 @@ package io.helidon.tracing.tests.it1; import java.net.URI; -import java.util.List; -import java.util.Map; - +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import io.helidon.common.context.Context; +import io.helidon.common.context.Contexts; import io.helidon.tracing.Span; import io.helidon.tracing.Tracer; import io.helidon.tracing.TracerBuilder; @@ -32,20 +37,21 @@ import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MultivaluedHashMap; import org.hamcrest.collection.IsEmptyCollection; -import org.hamcrest.collection.IsMapContaining; -import org.hamcrest.core.Is; -import org.hamcrest.core.IsCollectionContaining; -import org.hamcrest.core.IsInstanceOf; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsMapContaining.hasEntry; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsCollectionContaining.hasItem; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.jupiter.api.Assertions.fail; /** * The ZipkinClientTest. */ -public class OpentraceableClientFilterTest { +class OpentraceableClientFilterTest { private final Tracer tracer = TracerBuilder.create("test-service").registerGlobal(false).build(); private final ClientTracingFilter filter = new ClientTracingFilter(); @@ -53,14 +59,14 @@ public class OpentraceableClientFilterTest { private final Configuration configurationMock = Mockito.mock(Configuration.class); private final ClientRequestContext requestContextMock; - public OpentraceableClientFilterTest() { + OpentraceableClientFilterTest() { this.requestContextMock = Mockito.mock(ClientRequestContext.class); Mockito.when(this.requestContextMock.getUri()).thenReturn(URI.create("http://localhost/foo/bar")); Mockito.when(this.requestContextMock.getMethod()).thenReturn("GET"); } @BeforeEach - public void connectMocks() throws Exception { + void connectMocks() { Mockito.doReturn(configurationMock) .when(requestContextMock) .getConfiguration(); @@ -71,55 +77,89 @@ public void connectMocks() throws Exception { } @Test - public void testNewSpanCreated() throws Exception { - Mockito.doReturn(tracer) - .when(requestContextMock) - .getProperty(Mockito.anyString()); - - filter.filter(requestContextMock); + void testNewSpanCreated() { + // this test leaves the span scope activated on current thread, so we run it in a different thread + runInThreadAndContext(() -> { + Mockito.doReturn(tracer) + .when(requestContextMock) + .getProperty(Mockito.anyString()); + + filter.filter(requestContextMock); + + assertThat(map, + hasEntry(is("X-B3-TraceId"), + hasItem(instanceOf(String.class)))); + String traceId = (String) map.getFirst("X-B3-TraceId"); + assertThat(map, hasEntry(is("X-B3-SpanId"), hasItem(is(traceId)))); + return null; + }); - assertThat(map, - IsMapContaining.hasEntry(Is.is("X-B3-TraceId"), - IsCollectionContaining.hasItem(IsInstanceOf.instanceOf(String.class)))); - String traceId = (String) map.getFirst("X-B3-TraceId"); - assertThat(map, IsMapContaining.hasEntry(Is.is("X-B3-SpanId"), IsCollectionContaining.hasItem(Is.is(traceId)))); } @Test - public void testChildSpanGetsCreated() throws Exception { - Mockito.doReturn(tracer) - .when(configurationMock) - .getProperty(ClientTracingFilter.TRACER_PROPERTY_NAME); - - Span span = tracer.spanBuilder("my-parent").start(); - - Mockito.doReturn(span.context()) - .when(requestContextMock) - .getProperty(ClientTracingFilter.CURRENT_SPAN_CONTEXT_PROPERTY_NAME); - - filter.filter(requestContextMock); - - TraceContext traceContext = ((BraveSpanContext) span.unwrap(io.opentracing.Span.class).context()).unwrap(); - assertThat(map, - IsMapContaining - .hasEntry(Is.is("X-B3-TraceId"), IsCollectionContaining.hasItem(Is.is(traceContext.traceIdString())))); - assertThat(map, - IsMapContaining.hasEntry(Is.is("X-B3-SpanId"), - IsCollectionContaining.hasItem(IsInstanceOf.instanceOf(String.class)))); - assertThat(map, - IsMapContaining.hasEntry(Is.is("X-B3-ParentSpanId"), - IsCollectionContaining.hasItem(Is.is(HexCodec.toLowerHex(traceContext.spanId()))))); - - for (Map.Entry> entry : map.entrySet()) { - System.out.println(entry.getKey() + " = " + entry.getValue()); - } + void testChildSpanGetsCreated() { + // this test leaves the span scope activated on current thread, so we run it in a different thread + runInThreadAndContext(() -> { + Mockito.doReturn(tracer) + .when(configurationMock) + .getProperty(ClientTracingFilter.TRACER_PROPERTY_NAME); + + Span span = tracer.spanBuilder("my-parent").start(); + + Mockito.doReturn(span.context()) + .when(requestContextMock) + .getProperty(ClientTracingFilter.CURRENT_SPAN_CONTEXT_PROPERTY_NAME); + + filter.filter(requestContextMock); + + TraceContext traceContext = ((BraveSpanContext) span.unwrap(io.opentracing.Span.class).context()).unwrap(); + assertThat(map, + hasEntry(is("X-B3-TraceId"), hasItem(is(traceContext.traceIdString())))); + assertThat(map, + hasEntry(is("X-B3-SpanId"), + hasItem(instanceOf(String.class)))); + assertThat(map, + hasEntry(is("X-B3-ParentSpanId"), + hasItem(is(HexCodec.toLowerHex(traceContext.spanId()))))); + + return null; + }); } @Test - public void testMissingTracer() throws Exception { + void testMissingTracer() { + // this test leaves the span scope activated on current thread, so we run it in a different thread - filter.filter(requestContextMock); + runInThreadAndContext(() -> { + filter.filter(requestContextMock); - assertThat(map.entrySet(), IsEmptyCollection.empty()); + assertThat(map.entrySet(), IsEmptyCollection.empty()); + return null; + }); + } + + private void runInThreadAndContext(Callable c) { + CompletableFuture cf = new CompletableFuture<>(); + + Thread thread = new Thread(() -> { + Contexts.runInContext(Context.create(), () -> { + try { + c.call(); + cf.complete(null); + } catch (Throwable e) { + cf.completeExceptionally(e); + } + }); + }); + thread.setDaemon(true); + thread.start(); + + try { + cf.get(10, TimeUnit.SECONDS); + } catch (InterruptedException | TimeoutException e) { + fail(e); + } catch (ExecutionException e) { + fail(e.getCause()); + } } } diff --git a/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpan.java b/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpan.java index edb40b72bfd..89347fcf403 100644 --- a/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpan.java +++ b/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpan.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * 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. @@ -31,9 +31,11 @@ */ class ZipkinSpan implements Span { private final Span span; + private final boolean isClient; - ZipkinSpan(Span span) { + ZipkinSpan(Span span, boolean isClient) { this.span = span; + this.isClient = isClient; } @Override @@ -43,13 +45,13 @@ public SpanContext context() { @Override public void finish() { - span.log("ss"); + finishLog(); span.finish(); } @Override public void finish(long finishMicros) { - span.log("ss"); + finishLog(); span.finish(finishMicros); } @@ -121,4 +123,12 @@ public Span setTag(Tag tag, T value) { Span unwrap() { return span; } + + private void finishLog() { + if (isClient) { + span.log("cr"); + } else { + span.log("ss"); + } + } } diff --git a/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpanBuilder.java b/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpanBuilder.java index 4dc00eead2d..44810e34066 100644 --- a/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpanBuilder.java +++ b/tracing/zipkin/src/main/java/io/helidon/tracing/zipkin/ZipkinSpanBuilder.java @@ -19,7 +19,6 @@ import java.util.List; import io.helidon.tracing.Tag; -import io.helidon.tracing.opentracing.OpenTracing; import io.opentracing.Span; import io.opentracing.SpanContext; @@ -36,6 +35,7 @@ class ZipkinSpanBuilder implements Tracer.SpanBuilder { private final Tracer tracer; private final Tracer.SpanBuilder spanBuilder; private final List> tags; + private boolean isClient; ZipkinSpanBuilder(Tracer tracer, Tracer.SpanBuilder spanBuilder, List> tags) { this.tracer = tracer; @@ -63,6 +63,9 @@ public Tracer.SpanBuilder addReference(String referenceType, SpanContext referen @Override public Tracer.SpanBuilder withTag(String key, String value) { + if ("span.kind".equals(key)) { + isClient = "client".equals(value); + } spanBuilder.withTag(key, value); return this; } @@ -88,12 +91,14 @@ public Tracer.SpanBuilder withStartTimestamp(long microseconds) { @Override public Span start() { Span span = spanBuilder.start(); - span.log("sr"); - io.helidon.tracing.Span helidonSpan = OpenTracing.create(tracer, span); - tags.forEach(tag -> tag.apply(helidonSpan)); + if (isClient) { + span.log("cs"); + } else { + span.log("sr"); + } - return new ZipkinSpan(span); + return new ZipkinSpan(span, isClient); } @Override From 13707ead9aa0160bdf47c548abe198f9d2f7ca79 Mon Sep 17 00:00:00 2001 From: Dmitry Aleksandrov Date: Tue, 29 Nov 2022 00:07:11 +0200 Subject: [PATCH 20/36] [4.x] - Fix Intermittent TestJBatchEndpoint.runJob (#5542) * Fix test for multiple try and errors. * Fix imports. --- .../examples/jbatch/TestJBatchEndpoint.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) 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 index 95a46f008a1..ac3fa679e5c 100644 --- a/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java +++ b/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java @@ -23,8 +23,8 @@ import jakarta.ws.rs.core.MediaType; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @HelidonTest @@ -45,18 +45,23 @@ public void runJob() throws InterruptedException { Integer responseJobId = jsonObject.getInt("Started a job with Execution ID: "); assertNotNull(responseJobId, "Response Job Id"); - //Wait a bit for it to complete - Thread.sleep(3000); + boolean result = false; + for (int i = 1; i < 10; i++) { + //Wait a bit for it to complete + Thread.sleep(i*1000); - //Examine the results - jsonObject = webTarget - .path("batch/status/" + responseJobId) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(JsonObject.class); + //Examine the results + jsonObject = webTarget + .path("batch/status/" + responseJobId) + .request(MediaType.APPLICATION_JSON_TYPE) + .get(JsonObject.class); + + String responseString = jsonObject.toString(); + result = responseString.equals("{\"Steps executed\":\"[step1, step2]\",\"Status\":\"COMPLETED\"}"); - String responseString = jsonObject.toString(); + if (result) break; + } - assertEquals("{\"Steps executed\":\"[step1, step2]\",\"Status\":\"COMPLETED\"}", - responseString, "Job Result string"); + assertTrue(result, "Job Result string"); } } From b01279db6e7de41bd3ae35f76747eeca28afb4a1 Mon Sep 17 00:00:00 2001 From: Andrii Serkes Date: Tue, 29 Nov 2022 00:35:43 +0100 Subject: [PATCH 21/36] 5377 custom exception for CharBuffer (#5505) * remove -Ddocker.build=true Signed-off-by: aserkes * fix copyrights Signed-off-by: aserkes * Create a custom exception to remove OutOfMemoryError in CharBuffer Signed-off-by: aserkes * remove unnecessary constructors Signed-off-by: aserkes Signed-off-by: aserkes --- .../reactive/media/common/CharBuffer.java | 2 +- .../media/common/OutOfCapacityException.java | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 reactive/media/common/src/main/java/io/helidon/reactive/media/common/OutOfCapacityException.java diff --git a/reactive/media/common/src/main/java/io/helidon/reactive/media/common/CharBuffer.java b/reactive/media/common/src/main/java/io/helidon/reactive/media/common/CharBuffer.java index e67d39af81e..8b27ffca636 100644 --- a/reactive/media/common/src/main/java/io/helidon/reactive/media/common/CharBuffer.java +++ b/reactive/media/common/src/main/java/io/helidon/reactive/media/common/CharBuffer.java @@ -97,7 +97,7 @@ private void grow(int minCapacity) { private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) { - throw new OutOfMemoryError("Capacity overflow. minCapacity=" + minCapacity); + throw new OutOfCapacityException("Capacity overflow. minCapacity=" + minCapacity); } return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE diff --git a/reactive/media/common/src/main/java/io/helidon/reactive/media/common/OutOfCapacityException.java b/reactive/media/common/src/main/java/io/helidon/reactive/media/common/OutOfCapacityException.java new file mode 100644 index 00000000000..3cde74d0a22 --- /dev/null +++ b/reactive/media/common/src/main/java/io/helidon/reactive/media/common/OutOfCapacityException.java @@ -0,0 +1,31 @@ +/* + * 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.reactive.media.common; + +/** + * Exception that is related to the capacity of an object. + */ +public class OutOfCapacityException extends RuntimeException { + + /** + * New exception with a message and without a cause. + * @param message message to use + */ + public OutOfCapacityException(String message) { + super(message); + } + +} From 9977d1e954204e1adcd7b7ca59c4b582fabf1729 Mon Sep 17 00:00:00 2001 From: Tim Quinn Date: Tue, 29 Nov 2022 06:14:13 -0600 Subject: [PATCH 22/36] Fix incorrect tags comparison when trying to match metric IDs (#5550) --- .../io/helidon/metrics/api/MetricStore.java | 10 ++- .../helidon/metrics/api/MetricStoreTests.java | 70 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/MetricStore.java b/metrics/api/src/main/java/io/helidon/metrics/api/MetricStore.java index 73443a39725..4535679ab39 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/MetricStore.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/MetricStore.java @@ -408,7 +408,7 @@ private HelidonMetric getMetricLocked(String metricName, Tag... tags) { return null; } for (MetricID metricID : metricIDsForName) { - if (metricID.getName().equals(metricName) && Arrays.equals(metricID.getTagsAsArray(), tags)) { + if (metricID.getName().equals(metricName) && tagsMatch(tags, metricID.getTags())) { return allMetrics.get(metricID); } } @@ -531,6 +531,14 @@ private S access(Lock lock, Callable action) { } } + private static boolean tagsMatch(Tag[] tags, Map tagMap) { + Map newTags = new TreeMap<>(); + for (Tag tag : tags) { + newTags.put(tag.getTagName(), tag.getTagValue()); + } + return newTags.equals(tagMap); + } + private static void enforceConsistentMetadata(Metadata existingMetadata, Metadata newMetadata) { if (!metadataMatches(existingMetadata, newMetadata)) { throw new IllegalArgumentException("New metadata conflicts with existing metadata with the same name; existing: " diff --git a/metrics/api/src/test/java/io/helidon/metrics/api/MetricStoreTests.java b/metrics/api/src/test/java/io/helidon/metrics/api/MetricStoreTests.java index 23670c17fb2..94f1618e2a8 100644 --- a/metrics/api/src/test/java/io/helidon/metrics/api/MetricStoreTests.java +++ b/metrics/api/src/test/java/io/helidon/metrics/api/MetricStoreTests.java @@ -23,6 +23,10 @@ import org.eclipse.microprofile.metrics.Tag; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + import static org.junit.jupiter.api.Assertions.assertThrows; class MetricStoreTests { @@ -56,4 +60,70 @@ void testConflictingMetadata() { assertThrows(IllegalArgumentException.class, () -> store.getOrRegisterMetric(meta2, Counter.class, NO_TAGS)); } + + @Test + void testSameNameNoTags() { + Metadata metadata = Metadata.builder() + .withName("a") + .withType(MetricType.COUNTER) + .build(); + + NoOpMetricRegistry registry = NoOpMetricRegistry.create(MetricRegistry.Type.APPLICATION); + + MetricStore store = MetricStore.create(REGISTRY_SETTINGS, + NoOpMetricRegistry.NO_OP_METRIC_FACTORIES, + null, + null, + MetricRegistry.Type.APPLICATION, + registry::toImpl); + + Counter counter1 = store.getOrRegisterMetric(metadata, Counter.class, NO_TAGS); + Counter counter2 = store.getOrRegisterMetric(metadata, Counter.class, NO_TAGS); + assertThat("Counters with no tags", counter1, is(counter2)); + } + + @Test + void testSameNameSameTwoTags() { + Tag[] tags = {new Tag("foo", "1"), new Tag("bar", "1")}; + Metadata metadata = Metadata.builder() + .withName("a") + .withType(MetricType.COUNTER) + .build(); + + NoOpMetricRegistry registry = NoOpMetricRegistry.create(MetricRegistry.Type.APPLICATION); + + MetricStore store = MetricStore.create(REGISTRY_SETTINGS, + NoOpMetricRegistry.NO_OP_METRIC_FACTORIES, + null, + null, + MetricRegistry.Type.APPLICATION, + registry::toImpl); + + Counter counter1 = store.getOrRegisterMetric(metadata, Counter.class, tags); + Counter counter2 = store.getOrRegisterMetric(metadata, Counter.class, tags); + assertThat("Counters with same two tags", counter1, is(counter2)); + } + + @Test + void testSameNameOverlappingButDifferentTags() { + Tag[] tags1 = {new Tag("foo", "1"), new Tag("bar", "1"), new Tag("baz", "1")}; + Tag[] tags2 = {new Tag("foo", "1"), new Tag("bar", "1")}; + Metadata metadata = Metadata.builder() + .withName("a") + .withType(MetricType.COUNTER) + .build(); + + NoOpMetricRegistry registry = NoOpMetricRegistry.create(MetricRegistry.Type.APPLICATION); + + MetricStore store = MetricStore.create(REGISTRY_SETTINGS, + NoOpMetricRegistry.NO_OP_METRIC_FACTORIES, + null, + null, + MetricRegistry.Type.APPLICATION, + registry::toImpl); + + Counter counter1 = store.getOrRegisterMetric(metadata, Counter.class, tags1); + Counter counter2 = store.getOrRegisterMetric(metadata, Counter.class, tags2); + assertThat("Counters with overlapping but different tags", counter1, not(is(counter2))); + } } From 03a01ebe8ab2d315790f54754fadad0ebdfad099 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Sat, 19 Nov 2022 00:47:54 -0500 Subject: [PATCH 23/36] config integration into builder --- bom/pom.xml | 12 + common/config/pom.xml | 27 + .../helidon/common/config/ConfigHolder.java | 105 +++ .../common/config/spi/ConfigProvider.java | 38 + .../common/config/spi/package-info.java | 20 + common/config/src/main/java/module-info.java | 5 + .../spi/testsubjects/TestConfigProvider.java | 46 + .../common/config/test/ConfigHolderTest.java | 51 ++ ...o.helidon.common.config.spi.ConfigProvider | 17 + .../processor/ConfigMetadataHandler.java | 4 +- pico/builder-config/builder-config/README.md | 3 + .../etc/spotbugs/checkstyle-suppressions.xml | 26 + .../builder-config/etc/spotbugs/exclude.xml | 33 + pico/builder-config/builder-config/pom.xml | 100 +++ .../pico/builder/config/ConfigBean.java | 99 ++ .../pico/builder/config/package-info.java | 20 + .../spi/ConfigBeanBuilderValidator.java | 192 ++++ .../spi/ConfigBeanBuilderValidatorHolder.java | 68 ++ .../ConfigBeanBuilderValidatorProvider.java | 33 + .../builder/config/spi/ConfigBeanInfo.java | 81 ++ .../builder/config/spi/ConfigBeanMapper.java | 40 + .../config/spi/ConfigBeanMapperHolder.java | 66 ++ .../config/spi/ConfigBeanMapperProvider.java | 33 + .../builder/config/spi/ConfigResolver.java | 71 ++ .../config/spi/ConfigResolverHolder.java | 58 ++ .../config/spi/ConfigResolverMapRequest.java | 48 + .../config/spi/ConfigResolverProvider.java | 31 + .../config/spi/ConfigResolverRequest.java | 60 ++ .../config/spi/DefaultConfigResolver.java | 120 +++ .../config/spi/GeneratedConfigBean.java | 48 + .../config/spi/GeneratedConfigBeanBase.java | 71 ++ .../spi/GeneratedConfigBeanBuilder.java | 61 ++ .../spi/GeneratedConfigBeanBuilderBase.java | 73 ++ .../config/spi/GeneratedConfigCommon.java | 62 ++ .../builder/config/spi/ResolutionCtx.java | 187 ++++ .../builder/config/spi/StringValueParser.java | 39 + .../config/spi/StringValueParserHolder.java | 58 ++ .../config/spi/StringValueParserProvider.java | 33 + .../pico/builder/config/spi/package-info.java | 20 + .../src/main/java/module-info.java | 36 + .../spi/test/ConfigBeanMapperHolderTest.java | 35 + .../ConfigBuilderValidatorHolderTest.java | 35 + .../spi/test/ConfigResolverHolderTest.java | 35 + .../spi/test/MetaConfigBeanInfoTest.java | 55 ++ .../spi/test/StringValueParserHolderTest.java | 35 + pico/builder-config/pom.xml | 42 + pico/builder-config/processor/README.md | 3 + pico/builder-config/processor/pom.xml | 78 ++ .../tools/ConfigBeanBuilderCreator.java | 389 ++++++++ .../config/processor/tools/package-info.java | 20 + .../processor/src/main/java/module-info.java | 38 + .../tests/ConfigBeanBuilderCreatorTest.java | 37 + .../builder-config/tests/configbean/README.md | 2 + pico/builder-config/tests/configbean/pom.xml | 142 +++ .../builder/config/fakes/FakeClientAuth.java | 49 + .../fakes/FakeComponentTracingConfig.java | 232 +++++ .../builder/config/fakes/FakeKeyConfig.java | 842 +++++++++++++++++ .../config/fakes/FakeKeystoreConfig.java | 134 +++ .../config/fakes/FakeNettyClientAuth.java | 26 + .../config/fakes/FakePathTracingConfig.java | 179 ++++ .../config/fakes/FakeRoutingConfig.java | 694 ++++++++++++++ .../config/fakes/FakeServerConfig.java | 763 ++++++++++++++++ .../config/fakes/FakeServerLifecycle.java | 37 + .../config/fakes/FakeSocketConfig.java | 847 +++++++++++++++++ .../fakes/FakeSpanLogTracingConfig.java | 129 +++ .../config/fakes/FakeSpanTracingConfig.java | 258 ++++++ .../config/fakes/FakeTraceableConfig.java | 55 ++ .../pico/builder/config/fakes/FakeTracer.java | 103 +++ .../config/fakes/FakeTracingConfig.java | 245 +++++ .../builder/config/fakes/FakeWebServer.java | 56 ++ .../config/fakes/FakeWebServerTlsConfig.java | 437 +++++++++ .../config/fakes/SSLContextConfig.java | 204 +++++ .../pico/builder/config/fakes/WebServer.java | 773 ++++++++++++++++ .../config/fakes/config/FakeClientAuth.java | 49 + .../config/FakeComponentTracingConfig.java | 223 +++++ .../config/fakes/config/FakeKeyConfig.java | 839 +++++++++++++++++ .../fakes/config/FakeKeystoreConfig.java | 132 +++ .../fakes/config/FakeNettyClientAuth.java | 26 + .../fakes/config/FakePathTracingConfig.java | 179 ++++ .../fakes/config/FakeRoutingConfig.java | 699 ++++++++++++++ .../config/fakes/config/FakeServerConfig.java | 763 ++++++++++++++++ .../fakes/config/FakeServerLifecycle.java | 38 + .../config/fakes/config/FakeSocketConfig.java | 849 ++++++++++++++++++ .../config/FakeSpanLogTracingConfig.java | 128 +++ .../fakes/config/FakeSpanTracingConfig.java | 258 ++++++ .../fakes/config/FakeTraceableConfig.java | 56 ++ .../config/fakes/config/FakeTracer.java | 103 +++ .../fakes/config/FakeTracingConfig.java | 244 +++++ .../fakes/config/FakeWebServerTlsConfig.java | 438 +++++++++ .../config/fakes/config/SSLContextConfig.java | 201 +++++ .../config/testsubjects/ClientConfig.java | 36 + .../config/testsubjects/CommonConfig.java | 36 + .../config/testsubjects/ServerConfig.java | 33 + .../configbean/src/main/java/module-info.java | 31 + .../config/test/BasicConfigBeanTest.java | 71 ++ pico/builder-config/tests/pom.xml | 49 + pico/builder/pom.xml | 5 + .../builder/processor/tools/BodyContext.java | 26 +- .../tools/DefaultBuilderCreator.java | 317 ++++--- .../processor/tools/GenerateJavadoc.java | 8 +- .../processor/tools/GenerateMethod.java | 6 +- ...sitor.java => GenerateVisitorSupport.java} | 6 +- pico/builder/tests/builder/pom.xml | 7 +- .../test/testsubjects/ComplexCase.java | 7 + .../builder/src/main/java/module-info.java | 3 +- .../builder/api/test/ComplexCaseTest.java | 3 +- pico/builder/tests/pom.xml | 9 + pico/pom.xml | 1 + .../helidon/pico/types/DefaultTypeName.java | 38 +- .../pico/types/test/DefaultTypeNameTest.java | 8 + 110 files changed, 14973 insertions(+), 156 deletions(-) create mode 100644 common/config/src/main/java/io/helidon/common/config/ConfigHolder.java create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/package-info.java create mode 100644 common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java create mode 100644 common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java create mode 100644 common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider create mode 100644 pico/builder-config/builder-config/README.md create mode 100644 pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml create mode 100644 pico/builder-config/builder-config/etc/spotbugs/exclude.xml create mode 100644 pico/builder-config/builder-config/pom.xml create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java create mode 100644 pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java create mode 100644 pico/builder-config/builder-config/src/main/java/module-info.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java create mode 100644 pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java create mode 100644 pico/builder-config/pom.xml create mode 100644 pico/builder-config/processor/README.md create mode 100644 pico/builder-config/processor/pom.xml create mode 100644 pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java create mode 100644 pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java create mode 100644 pico/builder-config/processor/src/main/java/module-info.java create mode 100644 pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java create mode 100644 pico/builder-config/tests/configbean/README.md create mode 100644 pico/builder-config/tests/configbean/pom.xml create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java create mode 100644 pico/builder-config/tests/configbean/src/main/java/module-info.java create mode 100644 pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java create mode 100644 pico/builder-config/tests/pom.xml rename pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/{GenerateVisitor.java => GenerateVisitorSupport.java} (97%) diff --git a/bom/pom.xml b/bom/pom.xml index aa97afec567..0a95049ff32 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -1425,6 +1425,18 @@ ${helidon.version} + + + io.helidon.pico.builder.config + helidon-pico-builder-config + ${helidon.version} + + + io.helidon.pico.builder.config + helidon-pico-builder-config-processor + ${helidon.version} + + diff --git a/common/config/pom.xml b/common/config/pom.xml index 8657f6c8175..4ee63f3e723 100644 --- a/common/config/pom.xml +++ b/common/config/pom.xml @@ -33,6 +33,33 @@ 11 + + + io.helidon.common + helidon-common + + + jakarta.inject + jakarta.inject-api + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-core + test + + + diff --git a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java new file mode 100644 index 00000000000..d84dc6e3b59 --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java @@ -0,0 +1,105 @@ +/* + * 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.common.config; + +import java.util.Objects; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.concurrent.atomic.AtomicReference; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.config.spi.ConfigProvider; + +/** + * Provides access to the global {@link io.helidon.common.config.Config} singleton instance. + *

+ * Most callers are simply expected to call the {@link #config()} method to resolve the global configuration. Note, however, + * that the global configuration instance needs to be made available prior to calling the {@link #config()} method. There are + * two techniques for establishing the global configuration instance: (1) via the Java {@link java.util.ServiceLoader} and + * (2) programmatically via the {@link #config(io.helidon.common.config.Config)} method. The {@link #config()} method will + * apply the following strategy to resolve and cache the global config instance: + *

    + *
  1. if the instance is already been established and cached then use it.
  2. + *
  3. if the instance has programmatically been set then use it - this is the same as the cached instance.
  4. + *
  5. use the service loader to resolve the config instance, and if found then cache it.
  6. + *
+ * Note also that the {@link #reset()} method can be used to clear the cached instance. However, doing so should not be expected + * to alter any callers that have previously obtained the global configuration instance prior to calling the {@link #reset()} + * method. + *

+ * Note that this class is not thread safe. If the global configuration must be set programmatically then it should therefore + * be set on the main thread typically early in the jvm lifecycle. + * + * @see io.helidon.common.config.spi.ConfigProvider + */ +public class ConfigHolder { + private static final AtomicReference> INSTANCE = new AtomicReference<>(); + + private ConfigHolder() { + } + + /** + * Returns the global {@link io.helidon.common.config.Config} instance. + * + * @return the global instance + */ + public static Optional config() { + if (Objects.isNull(INSTANCE.get())) { + INSTANCE.set(load()); + } + return INSTANCE.get(); + } + + /** + * Proactively set the global configuration instance. Callers are reminded that {@link #reset()} must be called in order + * to clear any previously set global instance. Failure to do so will result in an exception being thrown. + * + * @param cfg the configuration + * @throws java.lang.IllegalStateException called if the config instance was previously been set + */ + public static void config(Config cfg) { + boolean set = INSTANCE.compareAndSet(null, + Optional.of(Objects.requireNonNull(cfg))); + if (!set) { + throw new IllegalStateException(Config.class.getSimpleName() + " already set"); + } + } + + /** + * Clears the config instance; not recommended for common use. + */ + public static void reset() { + System.Logger.Level level = Objects.nonNull(INSTANCE.get()) ? System.Logger.Level.INFO : System.Logger.Level.DEBUG; + System.Logger logger = System.getLogger(ConfigHolder.class.getName()); + logger.log(level, "resetting..."); + INSTANCE.set(null); + } + + private static Optional load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigProvider.class, ConfigProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return provider.get().__config(); + } + +} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java new file mode 100644 index 00000000000..df73647af6e --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java @@ -0,0 +1,38 @@ +/* + * 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.common.config.spi; + +import java.util.Optional; + +import io.helidon.common.config.Config; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link io.helidon.common.config.Config} instance. + * + * @see io.helidon.common.config.ConfigHolder + */ +public interface ConfigProvider { + + /** + * The service-loaded global {@link io.helidon.common.config.Config} instance. + * + * @return the global config instance + */ + // note that this needs to have double underscore since it is available in generated code + Optional __config(); + +} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/package-info.java b/common/config/src/main/java/io/helidon/common/config/spi/package-info.java new file mode 100644 index 00000000000..387ce4be611 --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Common Config SPI. + */ +package io.helidon.common.config.spi; diff --git a/common/config/src/main/java/module-info.java b/common/config/src/main/java/module-info.java index 789c2d599f3..86500ceda0f 100644 --- a/common/config/src/main/java/module-info.java +++ b/common/config/src/main/java/module-info.java @@ -18,5 +18,10 @@ * Helidon Common Config Library. */ module io.helidon.common.config { + requires io.helidon.common; + + uses io.helidon.common.config.spi.ConfigProvider; + exports io.helidon.common.config; + exports io.helidon.common.config.spi; } diff --git a/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java b/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java new file mode 100644 index 00000000000..b23b02af85b --- /dev/null +++ b/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java @@ -0,0 +1,46 @@ +/* + * 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.common.config.spi.testsubjects; + +import java.util.Optional; + +import io.helidon.common.config.Config; +import io.helidon.common.config.ConfigValue; +import io.helidon.common.config.spi.ConfigProvider; + +import jakarta.inject.Singleton; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@Singleton +@SuppressWarnings("unchecked") +@Deprecated +public class TestConfigProvider implements ConfigProvider { + + @Override + public Optional __config() { + ConfigValue val = mock(ConfigValue.class); + when(val.get()).thenReturn("mock"); + + Config cfg = mock(Config.class); + when(cfg.asString()).thenReturn(val); + + return Optional.of(cfg); + } + +} diff --git a/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java b/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java new file mode 100644 index 00000000000..077baf6216a --- /dev/null +++ b/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.common.config.test; + +import java.util.Optional; + +import io.helidon.common.config.Config; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.config.ConfigHolder.config; +import static io.helidon.common.config.ConfigHolder.reset; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + +class ConfigHolderTest { + + @Test + void testConfig() { + Optional cfg = config(); + assertThat(cfg.orElseThrow().asString().get(), is("mock")); + + Config mockCfg = mock(Config.class); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> config(mockCfg)); + assertThat(e.getMessage(), + equalTo(Config.class.getSimpleName() + " already set")); + + reset(); + config(mockCfg); + assertThat(config().orElseThrow(), sameInstance(mockCfg)); + } + +} diff --git a/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider b/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider new file mode 100644 index 00000000000..10c33bdb78d --- /dev/null +++ b/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider @@ -0,0 +1,17 @@ +# +# 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. +# + +io.helidon.common.config.spi.testsubjects.TestConfigProvider 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 index 1880666508f..ea462ed895d 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 @@ -728,7 +728,9 @@ List findConfiguredOptionAnnotations(ExecutableElement element /* Method name is camel case (such as maxInitialLineLength) - result is dash separated and lower cased (such as max-initial-line-length) + 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. */ String toConfigKey(String methodName) { StringBuilder result = new StringBuilder(methodName.length() + 5); diff --git a/pico/builder-config/builder-config/README.md b/pico/builder-config/builder-config/README.md new file mode 100644 index 00000000000..0d1b5cf22a9 --- /dev/null +++ b/pico/builder-config/builder-config/README.md @@ -0,0 +1,3 @@ +# pico-builder-config + +This module can be used at compile time and runtime. diff --git a/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml b/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml new file mode 100644 index 00000000000..4b9dc6e150d --- /dev/null +++ b/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/pico/builder-config/builder-config/etc/spotbugs/exclude.xml b/pico/builder-config/builder-config/etc/spotbugs/exclude.xml new file mode 100644 index 00000000000..8bf694d04c5 --- /dev/null +++ b/pico/builder-config/builder-config/etc/spotbugs/exclude.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/pico/builder-config/builder-config/pom.xml b/pico/builder-config/builder-config/pom.xml new file mode 100644 index 00000000000..8918384dd6e --- /dev/null +++ b/pico/builder-config/builder-config/pom.xml @@ -0,0 +1,100 @@ + + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + helidon-pico-builder-config + + Helidon Pico Config Builder API / SPI + + + true + + + + + + + io.helidon.pico.builder + helidon-pico-builder + + + io.helidon.common + helidon-common-config + + + jakarta.inject + jakarta.inject-api + provided + + + io.helidon.config + helidon-config-metadata + provided + + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -XprintProcessorInfo + -XprintRounds + -verbose + + true + + + io.helidon.pico.builder + helidon-pico-builder-processor + ${helidon.version} + + + + + + + diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java new file mode 100644 index 00000000000..ae24ae907a6 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java @@ -0,0 +1,99 @@ +/* + * 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.pico.builder.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import io.helidon.pico.builder.BuilderTrigger; + +/** + * A {@code ConfigBean} is another {@link io.helidon.pico.builder.BuilderTrigger} which extends the + * {@link io.helidon.pico.builder.Builder} concept in support of integration to Helidon's configuration sub-system. It provides + * everything that {@link io.helidon.pico.builder.Builder} provides. However, unlike the base + * {@link io.helidon.pico.builder.Builder} generated classes which can handle any object type, the types used within your target + * {@code ConfigBean}-annotated interface must have all of its attribute getter method types resolvable by Helidon's configuration + * sub-system. + *

+ * One should write a {@code ConfigBean}-annotated interface in such a way as to group the collection of configurable elements + * that logically belong together to then be delivered (and perhaps trigger an activation of) one or more java service types that + * are said to be {@code ConfiguredBy} the given {@link ConfigBean} instance. + *

+ * The {@code pico-builder-config-processor} module is required to be on the APT classpath to code-generate the implementation + * classes for the {@code ConfigBean}. + *

+ * Example: + *

{@code
+ * @ConfigBean
+ * public interface MyConfigBean {
+ *     String getName();
+ *     int getPort();
+ * }
+ * }
+ *

+ * When {@code Pico} services and config-service modules are incorporated into the application lifecycle, the configuration + * sub-system is scanned at startup and {@code ConfigBean} instances are created and fed into the {@code ConfigBeanRegistry}. + * This mapping occurs based upon the {@link io.helidon.config.metadata.ConfiguredOption#key()} applied on the {@code ConfigBean} + * interface type. If no such declaration is found, then the type name is used as the key (e.g., MyConfigBean would map to + * "my-config-bean"). + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(java.lang.annotation.ElementType.TYPE) +@BuilderTrigger +public @interface ConfigBean { + + /** + * Determines whether an instance of this config bean in the bean registry will result in the backing service + * {@code ConfiguredBy} this bean to be activated. + * + * @return true if this config bean should drive {@code ConfiguredBy} service activation + */ + boolean drivesActivation() default true; + + /** + * An instance of this bean will be created if there are no instances discovered by the configuration provider(s) post + * startup, and will use all default values annotated using {@code ConfiguredOptions} from the bean interface methods. + * + * @return the default config bean instance using defaults + */ + boolean atLeastOne() default false; + + /** + * Determines whether there can be more than one bean instance of this type. + *

+ * If false then only 0..1 behavior will be permissible for active beans in the config registry. If true then {@code > 1} + * instances will be permitted. The default values is {@code true}. + *

+ * Note: this attribute is dynamic in nature, and therefore cannot be validated at compile time. All violations found to this + * policy will be observed during PicoServices activation. + * + * @return true if repeatable + */ + boolean repeatable() default true; + + /** + * The overridden key to use. If not set this will default to use the expanded name from the config subsystem, + * (e.g. MyConfig -> "my-config"). + * + * @return the overriding key to use + */ + String key() default ""; + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java new file mode 100644 index 00000000000..bf8cfa090f8 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Helidon Pico Config Builder API. + */ +package io.helidon.pico.builder.config; diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java new file mode 100644 index 00000000000..9d0a38d42a7 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java @@ -0,0 +1,192 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +import io.helidon.pico.builder.AttributeVisitor; + +/** + * Validates a {@link io.helidon.pico.builder.config.ConfigBean} generated builder type instance bean the builder build() is + * called and the result is consumed. + * + * @param the config bean builder type + */ +@FunctionalInterface +public interface ConfigBeanBuilderValidator { + + /** + * Creates a validation round for all the config bean attributes of the provided config bean. + * + * @param builder the config builder instance + * @param configBeanBuilderType the config bean type + * @return the validation round that can be used for attribute level validation + */ + ValidationRound createValidationRound(CBB builder, + Class configBeanBuilderType); + + + /** + * The validation issue severity level. + * @see ConfigBeanBuilderValidator.ValidationIssue#getSeverity() + */ + enum Severity { + + /** + * A warning level. + */ + WARNING, + + /** + * An error level. + */ + ERROR + + } + + + /** + * Represents a single round of validation. A single round of validation will iterate over each attributes of the + * config bean, calling {@link #validate(String, Supplier, Class, java.util.Map)} for each attribute. + */ + interface ValidationRound extends AttributeVisitor { + + /** + * All the issues found. + * + * @return all issues found + */ + List getIssues(); + + /** + * Returns true if there were any issues found including warnings or errors. + * + * @return true if any issues were found + */ + default boolean hasIssues() { + return !getIssues().isEmpty(); + } + + /** + * Returns true if any errors were found. + * + * @return true if any issues were found of type {@link ConfigBeanBuilderValidator.Severity#ERROR} + */ + default boolean hasErrors() { + return getIssues().stream().anyMatch(it -> it.getSeverity() == Severity.ERROR); + } + + /** + * Returns true if the validation round is completed. + * + * @return true if the validation round is completed + * @see #finish(boolean) + */ + boolean isCompleted(); + + /** + * Performs a validation for a single attribute. + * + * @param attributeName the attribute name being validated + * @param valueSupplier the value supplier for the attribute + * @param meta the meta attributes for this attribute type + * @param cbType the attribute type + * @return the validation round continuation as a fluent-builder + */ + ValidationRound validate(String attributeName, Supplier valueSupplier, Class cbType, Map meta); + + @Override + default void visit(String attributeName, + Supplier valueSupplier, + Map meta, + Object userDefinedCtx, + Class cbType, + Class... ignored) { + validate(attributeName, valueSupplier, cbType, meta); + } + + /** + * Finishes the validation round, and will optionally throw a runtime exception if any error issues were found. + * + * @param throwIfErrors flag to indicate whether an exception should be raised if any errors were found + * @return the fluent builder for this round + * @throws java.lang.IllegalStateException if there were any validation errors in the round + */ + ValidationRound finish(boolean throwIfErrors); + } + + + /** + * Represents an issue that was encountered during + * {@link ValidationRound#validate(String, java.util.function.Supplier, Class, java.util.Map)}. + */ + class ValidationIssue { + private final Severity severity; + private final String attributeName; + private final String message; + + /** + * Constructs a new validation issue. + * + * @param severity the severity + * @param attributeName the attribute name in question + * @param message the message + */ + public ValidationIssue(Severity severity, String attributeName, String message) { + this.severity = Objects.requireNonNull(severity); + this.attributeName = Objects.requireNonNull(attributeName); + this.message = Objects.requireNonNull(message); + } + + /** + * Return the severity. + * + * @return the severity + */ + public Severity getSeverity() { + return severity; + } + + /** + * Returns the attribute name in question. + * + * @return the attribute name + */ + public String getAttributeName() { + return attributeName; + } + + /** + * Returns the user-friendly message. + * + * @return the user-friendly message + */ + public String getMessage() { + return message; + } + + @Override + public String toString() { + return getMessage(); + } + + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java new file mode 100644 index 00000000000..8072d6430b3 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorHolder.java @@ -0,0 +1,68 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link ConfigBeanBuilderValidator}. + * + * @see ConfigBeanBuilderValidatorProvider + */ +public class ConfigBeanBuilderValidatorHolder { + private static final LazyValue>> INSTANCE = + LazyValue.create(ConfigBeanBuilderValidatorHolder::load); + + private ConfigBeanBuilderValidatorHolder() { + } + + /** + * Provides the global service-loader instance of {@link ConfigBeanBuilderValidator}. + *

+ * Note that the current expectation here is that the global instance is capable for validating any + * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. The parameter used for the configBeanBuilderType serves + * to both type case the validator, and also reserves the possibility that the returned instance may be nuanced per builder + * type at some point in the future. + * + * @param configBeanBuilderType the config bean builder type to validate + * @param the config bean builder type + * @return the config bean builder validator + */ + @SuppressWarnings({"rawTypes", "unchecked"}) + public static Optional> configBeanValidatorFor(Class configBeanBuilderType) { + return (Optional) INSTANCE.get(); + } + + private static Optional> load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigBeanBuilderValidatorProvider.class, + ConfigBeanBuilderValidatorProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().configBeanBuilderValidator()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java new file mode 100644 index 00000000000..ece42d72d74 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link ConfigBeanBuilderValidator} instance. + * + * @see ConfigBeanBuilderValidatorHolder + */ +public interface ConfigBeanBuilderValidatorProvider { + + /** + * The service-loaded global {@link ConfigBeanBuilderValidator} instance. + * + * @return the global config bean builder validator instance + */ + ConfigBeanBuilderValidator configBeanBuilderValidator(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java new file mode 100644 index 00000000000..aa03bd9d607 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java @@ -0,0 +1,81 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Objects; + +import io.helidon.pico.builder.Builder; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * Represents all the attributes belonging to {@link io.helidon.pico.builder.config.ConfigBean} available in a + * {@link io.helidon.pico.builder.Builder} style usage pattern. + */ +@Builder(implPrefix = "Meta") +public interface ConfigBeanInfo extends ConfigBean { + + /** + * Builds meta information appropriate for config integration from a + * {@link io.helidon.pico.builder.config.ConfigBean} instance. This will use the key if {@link #key()} is present, and + * if not present will default to the simple class name of the bean type. + * + * @param val the config bean instance + * @param cfgBeanType the config bean type + * @return the meta information for the config bean + */ + static MetaConfigBeanInfo toMetaConfigBeanInfo(ConfigBean val, + Class cfgBeanType) { + Objects.requireNonNull(cfgBeanType); + MetaConfigBeanInfo.Builder builder = MetaConfigBeanInfo.toBuilder(Objects.requireNonNull(val)); + String key = val.key(); + if (!key.isBlank()) { + builder.key(toConfigKey(cfgBeanType.getSimpleName())); + } + return builder.build(); + } + + /** + * Converts the name (i.e., simple class name or method name) into a config key. + *

+ * Method name is camel case (such as maxInitialLineLength) + * result is dash separated and lower cased (such as max-initial-line-length). + * + * @param name the input name + * @return the config key + */ + // note: this method is also found in ConfigMetadataHandler. + static String toConfigKey(String name) { + StringBuilder result = new StringBuilder(name.length() + 5); + + char[] chars = name.toCharArray(); + for (char aChar : chars) { + if (Character.isUpperCase(aChar)) { + if (result.length() == 0) { + result.append(Character.toLowerCase(aChar)); + } else { + result.append('-') + .append(Character.toLowerCase(aChar)); + } + } else { + result.append(aChar); + } + } + + return result.toString(); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java new file mode 100644 index 00000000000..a71e423257d --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java @@ -0,0 +1,40 @@ +/* + * 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.pico.builder.config.spi; + +import io.helidon.common.config.Config; + +/** + * Maps a {@link io.helidon.common.config.Config} instance to a newly created + * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type instance. + * + * @param the config bean type + */ +@FunctionalInterface +public interface ConfigBeanMapper { + + /** + * Translate the provided configuration into the appropriate config bean for this service type. + * + * @param cfg the config + * @param configBeanType the config bean type + * @return the config bean generated + */ + CB toConfigBean(Config cfg, + Class configBeanType); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java new file mode 100644 index 00000000000..f287390a360 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java @@ -0,0 +1,66 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link ConfigBeanMapper}. + * + * @see ConfigBeanMapperProvider + */ +public class ConfigBeanMapperHolder { + private static final LazyValue>> INSTANCE = LazyValue.create(ConfigBeanMapperHolder::load); + + private ConfigBeanMapperHolder() { + } + + /** + * Provides the global service-loader instance of {@link ConfigBeanMapper}. + *

+ * Note that the current expectation here is that the global instance is capable for mapping any + * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. The parameter used for the configBeanType serves + * to both type case the mapper, and also reserves the possibility that the returned instance may be nuanced per bean + * type at some point in the future. + * + * @param configBeanType the config bean type to map + * @param the config bean type + * @return the config bean mapper + */ + @SuppressWarnings({"rawTypes", "unchecked"}) + public static Optional> configBeanMapperFor(Class configBeanType) { + return (Optional) INSTANCE.get(); + } + + private static Optional> load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigBeanMapperProvider.class, ConfigBeanMapperProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().configBeanMapper()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java new file mode 100644 index 00000000000..eac42ff3c4d --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link ConfigBeanMapper} instance. + * + * @see ConfigBeanMapperHolder + */ +public interface ConfigBeanMapperProvider { + + /** + * The service-loaded global {@link ConfigBeanMapper} instance. + * + * @return the global config bean mapper instance + */ + ConfigBeanMapper configBeanMapper(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java new file mode 100644 index 00000000000..bd9d0fd9b81 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java @@ -0,0 +1,71 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +/** + * Contract for resolving a configuration builder attribute element to the backing {@link io.helidon.common.config.Config}. + */ +public interface ConfigResolver { + + /** + * Resolves a {@link io.helidon.pico.builder.config.ConfigBean} singular element value from the + * backing {@link io.helidon.common.config.Config}. + * + * @param ctx the resolution context + * @param meta the meta attributes for this config bean + * @param request the request + * @param the attribute value type being resolved in the request + * @return the resolved value or empty if unable to resolve the request + */ + Optional of(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request); + + /** + * Resolves a {@link io.helidon.pico.builder.config.ConfigBean} collection-like element value from the + * backing {@link io.helidon.common.config.Config}. + * + * @param ctx the resolution context + * @param meta the meta attributes for this config bean + * @param request the request + * @param the attribute value type being resolved in the request + * @return the resolved value or empty if unable to resolve the request + */ + Optional> ofCollection(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request); + + /** + * Resolves a {@link io.helidon.pico.builder.config.ConfigBean} map-like element value from the + * backing {@link io.helidon.common.config.Config}. + * + * @param ctx the resolution context + * @param meta the meta attributes for this config bean + * @param request the request + * @param the map attribute key type being resolved in the request + * @param the map attribute value type being resolved in the request + * @return the resolved value or empty if unable to resolve the request + */ + Optional> ofMap(ResolutionCtx ctx, + Map> meta, + ConfigResolverMapRequest request); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java new file mode 100644 index 00000000000..d71ec21bd0a --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java @@ -0,0 +1,58 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link ConfigResolver}. + * + * @see ConfigResolverProvider + */ +public class ConfigResolverHolder { + private static final LazyValue> INSTANCE = LazyValue.create(ConfigResolverHolder::load); + + private ConfigResolverHolder() { + } + + /** + * Provides the global service-loader instance of {@link ConfigResolver}. + * + * @return the config resolver + */ + public static Optional configResolver() { + return INSTANCE.get(); + } + + private static Optional load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(ConfigResolverProvider.class, ConfigResolverProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().configResolver()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java new file mode 100644 index 00000000000..b1b12ff1b7d --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java @@ -0,0 +1,48 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * An extension of {@link io.helidon.pico.builder.config.spi.ConfigResolverRequest} for handling {@link java.util.Map}-like + * requests into {@link io.helidon.pico.builder.config.spi.ConfigResolver}. + * + * @param the key type + * @param the value type + */ +@Builder +public interface ConfigResolverMapRequest extends ConfigResolverRequest { + + /** + * The key type of the map attribute. + * + * @return the key type of the map attribute + */ + Class keyType(); + + /** + * The generic component type of the {@link #keyType()}. For example, this would be "String" for + * {@code Optional}. + * + * @return the component type + */ + Optional> keyComponentType(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java new file mode 100644 index 00000000000..bc37b31eca9 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java @@ -0,0 +1,31 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface to find implementation of {@link ConfigResolver}. + */ +public interface ConfigResolverProvider { + + /** + * Provide the {@link ConfigResolver} implementation. + * + * @return config resolver + */ + ConfigResolver configResolver(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java new file mode 100644 index 00000000000..4c200077b3f --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java @@ -0,0 +1,60 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * Used in conjunction with {@link io.helidon.pico.builder.config.spi.ConfigResolver}. + * + * @param the attribute value type being resolved + */ +@Builder +public interface ConfigResolverRequest { + + /** + * The configuration key. + * + * @return the optional configuration key + */ + String configKey(); + + /** + * The config builder attribute name - which is typically the same as the method name. + * + * @return the config builder attribute name + */ + String attributeName(); + + /** + * The type of the attribute value. + * + * @return the type of the attribute value + */ + Class valueType(); + + /** + * The generic component type of the {@link #valueType()}. For example, this would be "String" for + * {@code Optional}. + * + * @return the value component type + */ + Optional> valueComponentType(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java new file mode 100644 index 00000000000..f2841c03157 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java @@ -0,0 +1,120 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +import io.helidon.common.Weight; +import io.helidon.common.Weighted; +import io.helidon.common.config.Config; +import io.helidon.common.config.ConfigValue; + +import jakarta.inject.Singleton; + +/** + * The default implementation of {@link ConfigResolver} simply resolves against {@link io.helidon.common.config.Config} directly. + */ +@Singleton +@Weight(Weighted.DEFAULT_WEIGHT - 1) +public class DefaultConfigResolver implements ConfigResolver, ConfigResolverProvider { + + /** + * Tag that represents meta information about the attribute. Used in the maps for various methods herein. + */ + public static final String TAG_META = "__meta"; + + /** + * Default constructor, service loader invoked. + */ + @Deprecated + public DefaultConfigResolver() { + } + + @Override + public ConfigResolver configResolver() { + return this; + } + + @Override + public Optional of(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request) { + Config attrCfg = ctx.config().get(request.configKey()); + return attrCfg.exists() + ? optionalWrappedConfig(attrCfg, meta, request) : Optional.empty(); + } + + @Override + @SuppressWarnings("unchecked") + public Optional> ofCollection(ResolutionCtx ctx, + Map> meta, + ConfigResolverRequest request) { + Config attrCfg = ctx.config().get(request.configKey()); + return attrCfg.exists() + ? (Optional>) optionalWrappedConfig(attrCfg, meta, request) : Optional.empty(); + } + + @Override + @SuppressWarnings("unchecked") + public Optional> ofMap(ResolutionCtx ctx, + Map> meta, + ConfigResolverMapRequest request) { + Config attrCfg = ctx.config().get(request.configKey()); + return attrCfg.exists() + ? (Optional>) optionalWrappedConfig(attrCfg, meta, request) : Optional.empty(); + } + + @SuppressWarnings("unchecked") + private Optional optionalWrappedConfig(Config attrCfg, + Map> meta, + ConfigResolverRequest request) { + Class componentType = request.valueComponentType().orElse(null); + Class type = request.valueType(); + final boolean isOptional = Optional.class.equals(type); + if (isOptional) { + type = request.valueComponentType().orElseThrow(); + } + final boolean isCharArray = (type.isArray() && char.class == type.getComponentType()); + if (isCharArray) { + type = String.class; + } + + try { + ConfigValue attrVal = attrCfg.as(type); + Object val = attrVal.get(); + if (isCharArray) { + val = ((String) val).toCharArray(); + } + + return Optional.of(isOptional ? (T) Optional.of(val) : (T) val); + } catch (Exception e) { + String typeName = toTypeNameDescription(request.valueType(), componentType); + String configKey = attrCfg.key().toString(); + throw new IllegalStateException("Failed to convert " + typeName + + " for attribute: " + request.attributeName() + + " and config key: " + configKey, e); + } + } + + private static String toTypeNameDescription(Class type, + Class componentType) { + return type.getTypeName() + "<" + componentType.getTypeName() + ">"; + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java new file mode 100644 index 00000000000..5fd2849c017 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java @@ -0,0 +1,48 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Reserved for internal use! + *

+ * Every {@link io.helidon.pico.builder.config.ConfigBean}-annotated type will also implement this contract. + * + * @deprecated this is for internal use only + */ +public interface GeneratedConfigBean extends GeneratedConfigCommon { + +/* + Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated + methods. If its necessary to have a 0 or 1-arg method then the convention of prefixing the method with two underscores should be + used. + */ + + /** + * Set the instance id of this config bean. + * + * @param val the new instance identifier + */ + void __instanceId(String val); + + /** + * Returns the existing instance identifier. + * + * @return the instance identifier + */ + String __instanceId(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java new file mode 100644 index 00000000000..9c07c600b79 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java @@ -0,0 +1,71 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Objects; +import java.util.Optional; + +import io.helidon.common.config.Config; + +/** + * Minimal implementation for the {@link GeneratedConfigCommon}. This is the base for generated config beans. + * + * @deprecated this is for internal use only + */ +public abstract class GeneratedConfigBeanBase implements GeneratedConfigCommon { + private Config cfg; + private String instanceId; + + /** + * Protected constructor for initializing the generated config bean instance variables. + */ + protected GeneratedConfigBeanBase() { + } + + @Override + public Optional __config() { + return Optional.ofNullable(cfg); + } + + /** + * Sets the config instance. + * + * @param cfg the config instance + */ + public void __config(Config cfg) { + this.cfg = Objects.requireNonNull(cfg); + } + + /** + * Returns the instance id assigned to this bean. + * + * @return the instance id assigned to this bean + */ + public String __instanceId() { + return instanceId; + } + + /** + * Assigns the instance id assigned to this bean. + * + * @param val the new instance id for this bean + */ + public void __instanceId(String val) { + instanceId = val; + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java new file mode 100644 index 00000000000..e1e302d1709 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java @@ -0,0 +1,61 @@ +/* + * 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.pico.builder.config.spi; + +import io.helidon.common.config.Config; + +/** + * Reserved for internal use! + *

+ * Every {@link io.helidon.pico.builder.config.ConfigBean}-annotated type will also implement this contract. + * + * @deprecated + */ +public interface GeneratedConfigBeanBuilder extends GeneratedConfigCommon { + +/* + Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated + methods. If its necessary to have a 0 or 1-arg method then the convention of prefixing the method with two underscores should be + used. + */ + + /** + * Copy values from the config, optionally applying the default resolver and validator. + * + * @param cfg the config to initialize the builder values + * @param resolveAndValidate if called will resolve and validate + * + * @see ConfigResolver + * @see ConfigBeanBuilderValidatorHolder + * @throws java.lang.IllegalStateException if there are any resolution or validation errors + */ + void acceptConfig(Config cfg, + boolean resolveAndValidate); + + /** + * Copy values from an existing builder. + * + * @param cfg the config to initialize the builder values + * @param resolver the resolver + * @param validator the validator + * @throws java.lang.IllegalStateException if there are any resolution or validation errors + */ + void acceptConfig(Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java new file mode 100644 index 00000000000..ad31a26f906 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java @@ -0,0 +1,73 @@ +/* + * 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.pico.builder.config.spi; + +import io.helidon.common.config.Config; + +/** + * Minimal implementation for the {@link GeneratedConfigBeanBuilder}. + * + * @deprecated this is for internal use only + */ +public abstract class GeneratedConfigBeanBuilderBase extends GeneratedConfigBeanBase implements GeneratedConfigBeanBuilder { + + /** + * Default constructor. Reserved for internal use. + */ + protected GeneratedConfigBeanBuilderBase() { + } + + @Override + public void acceptConfig(Config cfg, + boolean resolveAndValidate) { + if (resolveAndValidate) { + // note: do not simplify this code by calling createResolutionContext - we want that to come from the generated code + acceptConfig(cfg, + ConfigResolverHolder.configResolver().get(), + ConfigBeanBuilderValidatorHolder.configBeanValidatorFor(__configBeanType()).orElse(null)); + } else { + __config(cfg); + } + } + + /** + * Creates a resolution context. + * + * @param configBeanType the config bean type + * @param cfg the config + * @param resolver the resolver + * @param validator the config bean builder validator + * @return the resolution context + */ + protected ResolutionCtx createResolutionContext(Class configBeanType, + Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator) { + // note to self: that in the future we should probably accept a code-generated 'version id' here --jtrent + return ResolutionCtx.create(configBeanType, cfg, resolver, validator); + } + + /** + * Called when finished the resolution process. + * + * @param ctx the resolution context + */ + protected void finishedResolution(ResolutionCtx ctx) { + // note to self: need to add validation here --jtrent + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java new file mode 100644 index 00000000000..7fb8dd030a6 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java @@ -0,0 +1,62 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +import io.helidon.common.config.Config; +import io.helidon.common.config.spi.ConfigProvider; +import io.helidon.pico.builder.AttributeVisitor; + +/** + * These methods are in common between generated config bean and config bean builder types. + * + * @deprecated this is for internal use only + */ +public interface GeneratedConfigCommon extends ConfigProvider { + +/* + Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated + methods. If its necessary to have a 0 or 1-arg method then the convention of prefixing the method with two underscores should be + used. + */ + + /** + * Returns the configuration assigned to the generated config bean. + * + * @return the configuration assigned + */ + @Override + Optional __config(); + + /** + * Returns the {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. + * + * @return the config bean type + */ + Class __configBeanType(); + + /** + * Visits all attributes with the provided {@link io.helidon.pico.builder.AttributeVisitor}. + * + * @param visitor the visitor + * @param userDefinedCtx any user-defined context + */ + void visitAttributes(AttributeVisitor visitor, + Object userDefinedCtx); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java new file mode 100644 index 00000000000..618ef1a2290 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java @@ -0,0 +1,187 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Objects; +import java.util.Optional; + +import io.helidon.common.config.Config; + +/** + * Config resolution process context. + */ +public class ResolutionCtx { + private final Class configBeanType; + private final Config cfg; + private final ConfigResolver resolver; + private final ConfigBeanBuilderValidator validator; + + /** + * Constructor for this type that takes a builder. + * + * @param b the builder + */ + protected ResolutionCtx(Builder b) { + this.configBeanType = Objects.requireNonNull(b.configBeanType); + this.cfg = Objects.requireNonNull(b.cfg); + this.resolver = Objects.requireNonNull(b.resolver); + this.validator = b.validator; + } + + /** + * Return the config bean type. + * + * @return the config bean type + */ + public Class configBeanType() { + return configBeanType; + } + + /** + * Return the config. + * + * @return the config + */ + public Config config() { + return cfg; + } + + /** + * Return the config resolver. + * + * @return the resolver + */ + public ConfigResolver resolver() { + return resolver; + } + + /** + * Return the config bean builder validator. + * + * @return the validator + */ + public Optional> validator() { + return Optional.ofNullable(validator); + } + + @Override + public String toString() { + return config().toString(); + } + + /** + * Creates a new fluent builder for this type. + * + * @return a fluent builder + */ + public static Builder builder() { + return new Builder(); + } + + + /** + * Creates a resolution context from the provided arguments. + * + * @param configBeanType the config bean type + * @param cfg the config + * @param resolver the resolver + * @param validator the bean builder validator + * @return the resolution context + */ + public static ResolutionCtx create(Class configBeanType, + Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator) { + return ResolutionCtx.builder() + .configBeanType(configBeanType) + .config(cfg) + .resolver(resolver) + .validator(validator) + .build(); + } + + /** + * Fluent builder for {@link io.helidon.pico.builder.config.spi.ResolutionCtx}. + */ + public static class Builder implements io.helidon.common.Builder { + private Class configBeanType; + private Config cfg; + private ConfigResolver resolver; + private ConfigBeanBuilderValidator validator; + + /** + * Constructor for the fluent builder. + */ + protected Builder() { + } + + /** + * Build the instance. + * + * @return the built instance + */ + @Override + public ResolutionCtx build() { + return new ResolutionCtx(this); + } + + /** + * Set the config bean type. + * + * @param configBeanType the config bean type + * @return this fluent builder + */ + public Builder configBeanType(Class configBeanType) { + this.configBeanType = Objects.requireNonNull(configBeanType); + return this; + } + + /** + * Set the config. + * + * @param val the config + * @return this fluent builder + */ + public Builder config(Config val) { + this.cfg = Objects.requireNonNull(val); + return identity(); + } + + /** + * Set the config resolver. + * + * @param val the config resolver + * @return this fluent builder + */ + public Builder resolver(ConfigResolver val) { + this.resolver = Objects.requireNonNull(val); + return identity(); + } + + /** + * Set the config bean builder validator. + * + * @param val the config validator + * @return this fluent builder + */ + public Builder validator(ConfigBeanBuilderValidator val) { + this.validator = val; + return identity(); + } + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java new file mode 100644 index 00000000000..03bfe6d5d19 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParser.java @@ -0,0 +1,39 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; + +/** + * String value parser. + */ +@FunctionalInterface +public interface StringValueParser { + + /** + * Parse the string into a type R instance. + * + * @param val the string value to parse + * @param type the type of the result expected + * @param the return type + * @return the optional nullable parsed value + * @throws java.lang.IllegalArgumentException if the format is not parsable or the return type is not supported + */ + Optional parse(String val, + Class type); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java new file mode 100644 index 00000000000..9c388f21e60 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java @@ -0,0 +1,58 @@ +/* + * 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.pico.builder.config.spi; + +import java.util.Optional; +import java.util.ServiceLoader; + +import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.LazyValue; + +/** + * Provides access to the {@link StringValueParser}. + * + * @see StringValueParserProvider + */ +public class StringValueParserHolder { + private static final LazyValue> INSTANCE = LazyValue.create(StringValueParserHolder::load); + + private StringValueParserHolder() { + } + + /** + * Provides the global service-loader instance of {@link StringValueParser}. + * + * @return the string value parser + */ + public static Optional stringValueParser() { + return INSTANCE.get(); + } + + private static Optional load() { + Optional provider = HelidonServiceLoader + .create(ServiceLoader.load(StringValueParserProvider.class, StringValueParserProvider.class.getClassLoader())) + .asList() + .stream() + .findFirst(); + if (provider.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(provider.get().stringValueParser()); + } + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java new file mode 100644 index 00000000000..31ec291e252 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserProvider.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.spi; + +/** + * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link StringValueParser} instance. + * + * @see io.helidon.pico.builder.config.spi.StringValueParserHolder + */ +public interface StringValueParserProvider { + + /** + * The service-loaded global {@link StringValueParser} instance. + * + * @return the global string value parser instance + */ + StringValueParser stringValueParser(); + +} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java new file mode 100644 index 00000000000..dbf48f19b7e --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Helidon Pico Config Builder SPI. + */ +package io.helidon.pico.builder.config.spi; diff --git a/pico/builder-config/builder-config/src/main/java/module-info.java b/pico/builder-config/builder-config/src/main/java/module-info.java new file mode 100644 index 00000000000..67c804cda28 --- /dev/null +++ b/pico/builder-config/builder-config/src/main/java/module-info.java @@ -0,0 +1,36 @@ +/* + * 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 Helidon Pico Config Builder API / SPI + */ +module io.helidon.pico.builder.config { + requires static jakarta.inject; + requires io.helidon.pico.builder; + requires io.helidon.common; + requires io.helidon.common.config; + + uses io.helidon.pico.builder.config.spi.ConfigBeanMapperProvider; + uses io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidatorProvider; + uses io.helidon.pico.builder.config.spi.ConfigResolverProvider; + uses io.helidon.pico.builder.config.spi.StringValueParserProvider; + + exports io.helidon.pico.builder.config; + exports io.helidon.pico.builder.config.spi; + + provides io.helidon.pico.builder.config.spi.ConfigResolverProvider + with io.helidon.pico.builder.config.spi.DefaultConfigResolver; +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java new file mode 100644 index 00000000000..0159d448ed7 --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBeanMapperHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.ConfigBeanMapperHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class ConfigBeanMapperHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(ConfigBeanMapperHolder.configBeanMapperFor(Object.class), + is(optionalEmpty())); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java new file mode 100644 index 00000000000..c39c20c2554 --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigBuilderValidatorHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidatorHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class ConfigBuilderValidatorHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(ConfigBeanBuilderValidatorHolder.configBeanValidatorFor(Object.class), + is(optionalEmpty())); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java new file mode 100644 index 00000000000..27f6ef116da --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/ConfigResolverHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.ConfigResolverHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalPresent; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class ConfigResolverHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(ConfigResolverHolder.configResolver(), + is(optionalPresent())); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java new file mode 100644 index 00000000000..e473fb1602f --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/MetaConfigBeanInfoTest.java @@ -0,0 +1,55 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.spi.ConfigBeanInfo; +import io.helidon.pico.builder.config.spi.MetaConfigBeanInfo; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@ConfigBean() +class MetaConfigBeanInfoTest { + + @Test + void testToMetaConfigBeanInfo() { + ConfigBean cfg = getClass().getAnnotation(ConfigBean.class); + assertNotNull(cfg); + MetaConfigBeanInfo metaCfg = ConfigBeanInfo.toMetaConfigBeanInfo(cfg, ConfigBean.class); + assertThat(metaCfg.annotationType(), sameInstance(ConfigBean.class)); + assertThat(metaCfg.repeatable(), is(true)); + assertThat(metaCfg.drivesActivation(), is(true)); + assertThat(metaCfg.atLeastOne(), is(false)); + assertThat(metaCfg.key(), is("")); + } + + @Test + void testToConfigKey() { + assertAll( + () -> assertThat(ConfigBeanInfo.toConfigKey("maxInitialLineLength"), is("max-initial-line-length")), + () -> assertThat(ConfigBeanInfo.toConfigKey("port"), is("port")), + () -> assertThat(ConfigBeanInfo.toConfigKey("listenAddress"), is("listen-address")) + ); + } + +} diff --git a/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java new file mode 100644 index 00000000000..20586ad83f0 --- /dev/null +++ b/pico/builder-config/builder-config/src/test/java/io/helidon/pico/builder/config/spi/test/StringValueParserHolderTest.java @@ -0,0 +1,35 @@ +/* + * 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.pico.builder.config.spi.test; + +import io.helidon.pico.builder.config.spi.StringValueParserHolder; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class StringValueParserHolderTest { + + @Test + void testGlobalInstanceIsEmpty() { + assertThat(StringValueParserHolder.stringValueParser(), + is(optionalEmpty())); + } + +} diff --git a/pico/builder-config/pom.xml b/pico/builder-config/pom.xml new file mode 100644 index 00000000000..f5a7de0346e --- /dev/null +++ b/pico/builder-config/pom.xml @@ -0,0 +1,42 @@ + + + + + + io.helidon.pico + helidon-pico-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + Helidon Pico Builder Config Project + pom + + + builder-config + processor + tests + + + diff --git a/pico/builder-config/processor/README.md b/pico/builder-config/processor/README.md new file mode 100644 index 00000000000..6d743bf762d --- /dev/null +++ b/pico/builder-config/processor/README.md @@ -0,0 +1,3 @@ +# pico-builder-config-processor + +This module should typically should be used at compile-time on the APt classpath. Also note that even though it is called processor it is not technically a processor, but rather a BuilderCreator extension to the base Builder processor. diff --git a/pico/builder-config/processor/pom.xml b/pico/builder-config/processor/pom.xml new file mode 100644 index 00000000000..b5edbd42e46 --- /dev/null +++ b/pico/builder-config/processor/pom.xml @@ -0,0 +1,78 @@ + + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + helidon-pico-builder-config-processor + + Helidon Pico Builder ConfigBean Processor + + + + io.helidon.pico.builder.config + helidon-pico-builder-config + + + io.helidon.pico.builder + helidon-pico-builder-processor + + + io.helidon.pico + helidon-pico-types + + + io.helidon.pico + helidon-pico + + + io.helidon.common + helidon-common-config + + + jakarta.inject + jakarta.inject-api + compile + + + jakarta.annotation + jakarta.annotation-api + provided + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java new file mode 100644 index 00000000000..65394f33cd6 --- /dev/null +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java @@ -0,0 +1,389 @@ +/* + * 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.pico.builder.config.processor.tools; + +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +import io.helidon.common.Weight; +import io.helidon.common.Weighted; +import io.helidon.common.config.Config; +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.Contract; +import io.helidon.pico.ExternalContracts; +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidator; +import io.helidon.pico.builder.config.spi.ConfigBeanInfo; +import io.helidon.pico.builder.config.spi.ConfigResolver; +import io.helidon.pico.builder.config.spi.DefaultConfigResolverRequest; +import io.helidon.pico.builder.config.spi.GeneratedConfigBeanBase; +import io.helidon.pico.builder.config.spi.GeneratedConfigBeanBuilderBase; +import io.helidon.pico.builder.config.spi.MetaConfigBeanInfo; +import io.helidon.pico.builder.config.spi.ResolutionCtx; +import io.helidon.pico.builder.processor.spi.TypeInfo; +import io.helidon.pico.builder.processor.tools.BodyContext; +import io.helidon.pico.builder.processor.tools.DefaultBuilderCreator; +import io.helidon.pico.types.AnnotationAndValue; +import io.helidon.pico.types.DefaultAnnotationAndValue; +import io.helidon.pico.types.DefaultTypeName; +import io.helidon.pico.types.TypeName; +import io.helidon.pico.types.TypedElementName; + +/** + * A specialization of {@link DefaultBuilderCreator} that supports the additional add-ons to the builder generated classes that + * binds to the config sub-system. + * + * @see io.helidon.pico.builder.config.spi.GeneratedConfigBean + * @see io.helidon.pico.builder.config.spi.GeneratedConfigBeanBuilder + */ +@Weight(Weighted.DEFAULT_WEIGHT) +public class ConfigBeanBuilderCreator extends DefaultBuilderCreator { + + /** + * Default constructor. + */ + // note: this needs to remain public since it will be resolved via service loader ... + @Deprecated + public ConfigBeanBuilderCreator() { + } + + @Override + public Set> supportedAnnotationTypes() { + return Collections.singleton(ConfigBean.class); + } + + @Override + protected void preValidate(TypeName implTypeName, + TypeInfo typeInfo, + AnnotationAndValue builderAnnotation) { + assertNoAnnotation(Contract.class.getName(), typeInfo); + assertNoAnnotation(ExternalContracts.class.getName(), typeInfo); + // note to self: add this when ConfiguredBy is introduced --jtrent +// assertNoAnnotation(ConfiguredBy.class.getName(), typeInfo); + assertNoAnnotation(jakarta.inject.Singleton.class.getName(), typeInfo); + assertNoAnnotation("javax.inject.Singleton", typeInfo); + } + + @Override + protected Optional baseExtendsTypeName(BodyContext ctx) { + return Optional.of(DefaultTypeName.create(GeneratedConfigBeanBase.class)); + } + + @Override + protected Optional baseExtendsBuilderTypeName(BodyContext ctx) { + return Optional.of(DefaultTypeName.create(GeneratedConfigBeanBuilderBase.class)); + } + + @Override + protected String instanceIdRef(BodyContext ctx) { + return "__instanceId()"; + } + + @Override + protected void appendExtraImports(StringBuilder builder, + BodyContext ctx) { + builder.append("\nimport ").append(AtomicInteger.class.getName()).append(";\n"); + builder.append("import ").append(Optional.class.getName()).append(";\n"); + builder.append("import ").append(Supplier.class.getName()).append(";\n\n"); + + super.appendExtraImports(builder, ctx); + + builder.append("import ").append(Config.class.getName()).append(";\n"); + builder.append("import ").append(ConfigResolver.class.getName()).append(";\n"); + builder.append("import ").append(ConfigBeanBuilderValidator.class.getName()).append(";\n"); + } + + @Override + protected void appendMetaAttributes(StringBuilder builder, + BodyContext ctx) { + if (ctx.doingConcreteType()) { + super.appendMetaAttributes(builder, ctx); + return; + } + + builder.append("\t@Override\n"); + builder.append("\tpublic Class __configBeanType() {\n" + + "\t\treturn ").append(ctx.typeInfo().typeName().name()).append(".class;\n" + + "\t}\n\n"); + javaDocMetaAttributesGetter(builder); + builder.append("\tpublic static Class __thisConfigBeanType() {\n" + + "\t\treturn ").append(ctx.typeInfo().typeName().name()).append(".class;\n" + + "\t}\n\n"); + + super.appendMetaAttributes(builder, ctx); + } + + @Override + protected void appendMetaProps(StringBuilder builder, + BodyContext ctx, + String tag, + AtomicBoolean needsCustomMapOf) { + builder.append("\t\t").append(tag); + builder.append(".put(\"__meta\", Map.of(").append(ConfigBeanInfo.class.getName()); + builder.append(".class.getName(),\n\t\t\t\t").append(MetaConfigBeanInfo.class.getName()).append(".builder()\n"); + appendConfigBeanInfoAttributes(builder, + ctx.typeInfo(), + DefaultAnnotationAndValue + .findFirst(ConfigBean.class.getTypeName(), + ctx.typeInfo().annotations()).orElseThrow()); + builder.append("\t\t\t\t\t\t.build()));\n"); + super.appendMetaProps(builder, ctx, tag, needsCustomMapOf); + } + + @Override + protected void appendExtraFields(StringBuilder builder, + BodyContext ctx) { + super.appendExtraFields(builder, ctx); + if (!ctx.hasParent() && !ctx.doingConcreteType()) { + builder.append("\tprivate static final AtomicInteger __INSTANCE_ID = new AtomicInteger();\n"); + } + } + + @Override + protected void appendExtraCtorCode(StringBuilder builder, + BodyContext ctx, + String builderTag) { + if (!ctx.hasParent()) { + builder.append("\t\t__instanceId(String.valueOf(__INSTANCE_ID.getAndIncrement()));\n"); + builder.append("\t\tif (b.__config().isPresent()) {\n" + + "\t\t\t__config(").append(builderTag).append(".__config().get());\n" + + "\t\t}\n"); + } + + super.appendExtraCtorCode(builder, ctx, builderTag); + } + + @Override + protected void appendExtraToBuilderBuilderFunctions(StringBuilder builder, + BodyContext ctx, + String decl) { + if (ctx.doingConcreteType()) { + String decl1 = decl.replace("{args}", Config.class.getName() + " cfg"); + javaDocToBuilder(builder, ctx, "cfg"); + builder.append("\t").append(decl1).append(" {\n"); + builder.append("\t\tBuilder b = builder();\n" + + "\t\tb.acceptConfig(cfg, true);\n" + + "\t\treturn b;\n" + + "\t}\n"); + } + + super.appendExtraToBuilderBuilderFunctions(builder, ctx, decl); + } + + @Override + protected void appendExtraBuilderMethods(StringBuilder builder, + BodyContext ctx) { + if (ctx.doingConcreteType()) { + super.appendExtraBuilderMethods(builder, ctx); + return; + } + + if (!ctx.hasParent()) { + builder.append("\t\t@Override\n"); + builder.append("\t\tpublic void acceptConfig" + + "(Config cfg, ConfigResolver resolver, ConfigBeanBuilderValidator validator) {\n"); + builder.append("\t\t\t").append(ResolutionCtx.class.getName()) + .append(" ctx = createResolutionContext(__configBeanType(), cfg, resolver, validator);\n"); + builder.append("\t\t\t__config(ctx.config());\n"); + builder.append("\t\t\t__acceptAndResolve(ctx);\n"); + builder.append("\t\t\tsuper.finishedResolution(ctx);\n"); + builder.append("\t\t}\n\n"); + } + + if (!ctx.doingConcreteType()) { + if (ctx.hasParent()) { + builder.append("\t\t@Override\n"); + } else { + javaDocAcceptResolveConfigCtx(builder, ctx, "ctx"); + } + builder.append("\t\tprotected void __acceptAndResolve(").append(ResolutionCtx.class.getName()).append(" ctx) {\n"); + if (ctx.hasParent()) { + builder.append("\t\t\tsuper.__acceptAndResolve(ctx);\n"); + } + + int i = 0; + for (String attrName : ctx.allAttributeNames()) { + TypedElementName method = ctx.allTypeInfos().get(i); + String configKey = toConfigKey(attrName, method, ctx.builderAnnotation()); + + // resolver.of(config, "port", int.class).ifPresent(this::port); + String ofClause = "of"; + TypeName outerType = method.typeName(); + String outerTypeName = outerType.declaredName(); + TypeName type = outerType; + String typeName = type.declaredName(); + TypeName mapKeyType = null; + TypeName mapKeyComponentType = null; + boolean isMap = typeName.equals(Map.class.getName()); + boolean isCollection = ( + typeName.equals(Collection.class.getName()) + || typeName.equals(Set.class.getName()) + || typeName.equals(List.class.getName())); + if (isCollection) { + ofClause = "ofCollection"; + type = type.typeArguments().get(0); + typeName = type.declaredName(); + } else if (isMap) { + ofClause = "ofMap"; + mapKeyType = type.typeArguments().get(0); + if (!mapKeyType.typeArguments().isEmpty()) { + mapKeyComponentType = mapKeyType.typeArguments().get(0); + } + type = type.typeArguments().get(1); + typeName = type.declaredName(); + } else if (Optional.class.getName().equals(typeName)) { + type = type.typeArguments().get(0); + typeName = type.declaredName(); + } + + builder.append("\t\t\tctx.resolver().").append(ofClause); + builder.append("(ctx, __metaAttributes(), ").append(DefaultConfigResolverRequest.class.getPackage().getName()); + builder.append(".DefaultConfigResolver"); + if (isMap) { + builder.append("Map"); + } + builder.append("Request.builder()\n\t\t\t\t\t"); + builder.append(".configKey(\"").append(configKey); + builder.append("\").attributeName(\"").append(attrName).append("\")"); + builder.append(".valueType(").append(outerTypeName).append(".class)"); + if (type != outerType) { + builder.append(".valueComponentType(").append(typeName).append(".class)"); + } + if (isMap) { + builder.append(".keyType(").append(Objects.requireNonNull(mapKeyType)).append(".class)"); + if (Objects.nonNull(mapKeyComponentType)) { + builder.append(".keyComponentType(").append(mapKeyComponentType.name()).append(".class)"); + } + } + builder.append(".build())\n\t\t\t\t\t.ifPresent((val) -> this.").append(method.elementName()).append("(("); + builder.append(outerTypeName).append(") val));\n"); + i++; + } + + builder.append("\t\t}\n\n"); + } + + builder.append("\t\t@Override\n"); + builder.append("\t\tpublic Class __configBeanType() {\n" + + "\t\t\treturn ") + .append(ctx.typeInfo().typeName().name()).append(".class;\n\t\t}\n\n"); + + super.appendExtraBuilderMethods(builder, ctx); + } + + @Override + protected boolean overridesVisitAttributes(BodyContext ctx) { + return true; + } + + private void appendConfigBeanInfoAttributes(StringBuilder builder, + TypeInfo typeInfo, + AnnotationAndValue configBeanAnno) { + String configKey = configBeanAnno.value("key").orElse(null); + configKey = normalizeConfiguredOptionKey(configKey, typeInfo.typeName().className(), null); + + builder.append("\t\t\t\t\t\t.key(\"") + .append(Objects.requireNonNull(configKey)).append("\")\n"); + builder.append("\t\t\t\t\t\t.repeatable(") + .append(configBeanAnno.value("repeatable").orElseThrow()).append(")\n"); + builder.append("\t\t\t\t\t\t.drivesActivation(") + .append(configBeanAnno.value("drivesActivation").orElseThrow()).append(")\n"); + builder.append("\t\t\t\t\t\t.atLeastOne(") + .append(configBeanAnno.value("atLeastOne").orElseThrow()).append(")\n"); + } + + private void javaDocMetaAttributesGetter(StringBuilder builder) { + builder.append("\t/**\n" + + "\t * Returns the {@code ConfigBean} type.\n" + + "\t *\n" + + "\t * @return the config bean type\n" + + "\t */\n"); + } + + private void javaDocToBuilder(StringBuilder builder, + BodyContext ctx, + String argTag) { + builder.append("\t/**\n" + + "\t * Creates a builder for this type, initialized with the Config value passed.\n" + + "\t *\n"); + builder.append("\t * @param ").append(argTag).append(" the config to copy and initialize from\n"); + builder.append("\t * @return a fluent builder for {@link ").append(ctx.typeInfo().typeName()); + builder.append("}\n\t */\n"); + } + + private void javaDocAcceptResolveConfigCtx(StringBuilder builder, + BodyContext ctx, + String argTag) { + builder.append("\t\t/**\n" + + "\t\t * Accept the config, resolves it, optionally validates.\n" + + "\t\t *\n"); + builder.append("\t\t * @param ").append(argTag).append(" the config resolution context\n"); + builder.append("\t\t */\n"); + } + + private String toConfigKey(String attrName, + TypedElementName method, + AnnotationAndValue ignoredBuilderAnnotation) { + String configKey = null; + Optional configuredOptions = DefaultAnnotationAndValue + .findFirst(ConfiguredOption.class.getName(), method.annotations()); + if (configuredOptions.isPresent()) { + configKey = configuredOptions.get().value("key").orElse(null); + } + if (Objects.isNull(configKey) || configKey.isBlank()) { + configKey = ConfigBeanInfo.toConfigKey(attrName); + } + return configKey; + } + + private void assertNoAnnotation(String annoTypeName, + TypeInfo typeInfo) { + Optional anno = DefaultAnnotationAndValue + .findFirst(annoTypeName, typeInfo.annotations()); + if (anno.isPresent()) { + throw new IllegalStateException(annoTypeName + " cannot be used in conjunction with " + + ConfigBean.class.getName() + + " on " + typeInfo.typeName()); + } + + for (TypedElementName elem : typeInfo.elementInfo()) { + anno = DefaultAnnotationAndValue.findFirst(annoTypeName, elem.annotations()); + if (anno.isEmpty()) { + anno = DefaultAnnotationAndValue.findFirst(annoTypeName, elem.elementTypeAnnotations()); + } + if (anno.isPresent()) { + throw new IllegalStateException(annoTypeName + " cannot be used in conjunction with " + + ConfigBean.class.getName() + + " on " + typeInfo.typeName() + "." + elem + "()"); + } + } + + if (typeInfo.superTypeInfo().isPresent()) { + assertNoAnnotation(annoTypeName, typeInfo.superTypeInfo().get()); + } + } + +} diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java new file mode 100644 index 00000000000..e6609e38653 --- /dev/null +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Pico ConfigBean Processor extensions. + */ +package io.helidon.pico.builder.config.processor.tools; diff --git a/pico/builder-config/processor/src/main/java/module-info.java b/pico/builder-config/processor/src/main/java/module-info.java new file mode 100644 index 00000000000..ad05aef5373 --- /dev/null +++ b/pico/builder-config/processor/src/main/java/module-info.java @@ -0,0 +1,38 @@ +/* + * 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 Pico ConfigBean Builder Processor (Tools) module. + */ +module io.helidon.pico.builder.config.processor { + requires jakarta.inject; + requires io.helidon.common; + requires io.helidon.common.config; + requires io.helidon.config.metadata; + requires io.helidon.pico.builder.config; + requires io.helidon.pico.builder.processor; + requires io.helidon.pico.builder.processor.spi; + requires io.helidon.pico.builder.processor.tools; + requires io.helidon.pico.types; + requires io.helidon.pico; + + exports io.helidon.pico.builder.config.processor.tools; + + uses io.helidon.pico.builder.processor.spi.BuilderCreator; + + provides io.helidon.pico.builder.processor.spi.BuilderCreator + with io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; +} diff --git a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java new file mode 100644 index 00000000000..5d921d05f3c --- /dev/null +++ b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java @@ -0,0 +1,37 @@ +/* + * 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.pico.builder.config.tools.tests; + +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; +import io.helidon.pico.builder.processor.spi.BuilderCreator; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + +class ConfigBeanBuilderCreatorTest { + + @Test + void supportedAnnotationTypes() { + BuilderCreator creator = new ConfigBeanBuilderCreator(); + assertEquals(1, creator.supportedAnnotationTypes().size()); + assertSame(ConfigBean.class, creator.supportedAnnotationTypes().iterator().next()); + } + +} diff --git a/pico/builder-config/tests/configbean/README.md b/pico/builder-config/tests/configbean/README.md new file mode 100644 index 00000000000..a9c613736c9 --- /dev/null +++ b/pico/builder-config/tests/configbean/README.md @@ -0,0 +1,2 @@ +# pico-builder-config-test-config +Tests for ConfigBean-generated builder types. diff --git a/pico/builder-config/tests/configbean/pom.xml b/pico/builder-config/tests/configbean/pom.xml new file mode 100644 index 00000000000..76648bbe2dc --- /dev/null +++ b/pico/builder-config/tests/configbean/pom.xml @@ -0,0 +1,142 @@ + + + + + + io.helidon.pico.builder.config.tests + helidon-pico-builder-config-tests-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + helidon-pico-builder-config-tests-test-config + Helidon Pico ConfigBean Tests + + + true + true + true + true + true + true + true + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config + + + io.helidon.config + helidon-config + test + + + jakarta.inject + jakarta.inject-api + provided + + + jakarta.annotation + jakarta.annotation-api + provided + + + io.helidon.pico.builder.config + helidon-pico-builder-config-processor + provided + + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -XprintProcessorInfo + -XprintRounds + -verbose + + true + + + io.helidon.pico.builder.config + helidon-pico-builder-config-processor + ${helidon.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + + diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java new file mode 100644 index 00000000000..65fb259f034 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes; + +/** + * Indicates whether the server requires authentication of tbe client by the certificate. + */ +public enum FakeClientAuth { + + /** + * Authentication is required. + */ + REQUIRE(FakeNettyClientAuth.REQUIRE), + + /** + * Authentication is optional. + */ + OPTIONAL(FakeNettyClientAuth.OPTIONAL), + + /** + * Authentication is not required. + */ + NONE(FakeNettyClientAuth.NONE); + + private final FakeNettyClientAuth clientAuth; + + FakeClientAuth(FakeNettyClientAuth clientAuth) { + this.clientAuth = clientAuth; + } + + FakeNettyClientAuth nettyClientAuth(){ + return clientAuth; + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java new file mode 100644 index 00000000000..05c0330801b --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java @@ -0,0 +1,232 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ComponentTracing. + * + * A component is a single "layer" of the application that can trace. + * Component examples: + *

    + *
  • web-server: webServer adds the root tracing span + two additional spans (content-read and content-write)
  • + *
  • security: security adds the overall request security span, a span for authentication ("security:atn"), a span for + * authorization "security:atz", and a span for response processing ("security:response")
  • + *
  • jax-rs: JAX-RS integration adds spans for overall resource invocation
  • + *
+ */ +@ConfigBean +public interface FakeComponentTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled component - all subsequent calls return disabled spans and logs. +// */ +// public static final ComponentTracingConfig DISABLED = ComponentTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * Enabled component - all subsequent calls return enabled spans and logs. +// */ +// public static final ComponentTracingConfig ENABLED = ComponentTracingConfig.builder("enabled").build(); + +// /** +// * A new named component. +// * +// * @param name name of the component +// */ +// protected ComponentTracingConfig(String name) { +// super(name); +// } +// + +// /** +// * Merge configuration of two traced components. This enabled hierarchical configuration +// * with common, default configuration in one traced component and override in another. +// * +// * @param older the older configuration with "defaults" +// * @param newer the newer configuration to override defaults in older +// * @return merged component +// */ +// static ComponentTracingConfig merge(ComponentTracingConfig older, ComponentTracingConfig newer) { +// return new ComponentTracingConfig(newer.name()) { +// @Override +// public Optional getSpan(String spanName) { +// if (!enabled()) { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// +// Optional newSpan = newer.getSpan(spanName); +// Optional oldSpan = older.getSpan(spanName); +// +// // both configured +// if (newSpan.isPresent() && oldSpan.isPresent()) { +// return Optional.of(SpanTracingConfig.merge(oldSpan.get(), newSpan.get())); +// } +// +// // only newer +// if (newSpan.isPresent()) { +// return newSpan; +// } +// +// return oldSpan; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of the span in this component +// * @return configuration of that span if present +// */ +// protected abstract Optional getSpan(String spanName); +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @return configuration of the span, or enabled configuration if not configured +// * @see #span(String, boolean) +// */ +// public SpanTracingConfig span(String spanName) { +// return span(spanName, true); +// } + + @Singular("span") // Builder::addSpan(String span, FakeSpanLogTracingConfigBean val), Impl::getSpan(String span), etc. + Map spanLogMap(); + +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @param enabledByDefault whether the result is enabled if a configuration is not present +// * @return configuration of the span, or a span configuration enabled or disabled depending on {@code enabledByDefault} if +// * not configured +// */ +// public SpanTracingConfig span(String spanName, boolean enabledByDefault) { +// if (enabled()) { +// return getSpan(spanName).orElseGet(() -> enabledByDefault ? SpanTracingConfig.ENABLED : SpanTracingConfig.DISABLED); +// } +// +// return SpanTracingConfig.DISABLED; +// } +// +// /** +// * Fluent API builder for traced component. +// * +// * @param name the name of the component +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced component configuration from {@link Config}. +// * +// * @param name name of the component +// * @param config config for a new component +// * @return a new traced component configuration +// */ +// public static ComponentTracingConfig create(String name, Config config) { +// return builder(name) +// .config(config) +// .build(); +// } +// +// /** +// * Fluent API builder for {@link ComponentTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map tracedSpans = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// private final String name; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public ComponentTracingConfig build() { +// // immutability +// final Optional finalEnabled = enabled; +// final Map finalSpans = new HashMap<>(tracedSpans); +// return new ComponentTracingConfig(name) { +// @Override +// public Optional getSpan(String spanName) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpans.get(spanName)); +// } else { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of a traced component +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("spans").asNodeList().ifPresent(spanConfigList -> { +// spanConfigList.forEach(spanConfig -> { +// // span name is mandatory +// addSpan(SpanTracingConfig.create(spanConfig.get("name").asString().get(), spanConfig)); +// }); +// }); +// return this; +// } +// +// /** +// * Add a new traced span configuration. +// * +// * @param span configuration of a traced span +// * @return updated builder instance +// */ +// public Builder addSpan(SpanTracingConfig span) { +// this.tracedSpans.put(span.name(), span); +// return this; +// } +// +// /** +// * Configure whether this component is enabled or disabled. +// * +// * @param enabled if disabled, all spans and logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java new file mode 100644 index 00000000000..fefe6cfd5cb --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java @@ -0,0 +1,842 @@ +/* + * 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.pico.builder.config.fakes; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * aka KeyConfig. + * + */ +@Builder +public interface FakeKeyConfig { + + // /*private static final*/ String DEFAULT_PRIVATE_KEY_ALIAS = "1"; +// /*private static final*/ char[] EMPTY_CHARS = new char[0]; + +// private static final Logger LOGGER = Logger.getLogger(FakeKeyConfigBean.class.getName()); +// +// private final PrivateKey privateKey; +// private final PublicKey publicKey; +// private final X509Certificate publicCert; +// private final List certChain = new LinkedList<>(); +// private final List certificates = new LinkedList<>(); +// +// private FakeKeyConfigBean(PrivateKey privateKey, +// PublicKey publicKey, +// X509Certificate publicCert, +// Collection certChain, +// Collection certificates) { +// +// this.privateKey = privateKey; +// this.publicKey = publicKey; +// this.publicCert = publicCert; +// this.certChain.addAll(certChain); +// this.certificates.addAll(certificates); +// } +// +// /** +// * Load key config from config. +// * +// * @param config config instance located at keys configuration (expects "keystore-path" child) +// * @return KeyConfig loaded from config +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// public static FakeKeyConfigBean create(Config config) throws PkiException { +// try { +// return fullBuilder().config(config).build(); +// } catch (ResourceException e) { +// throw new PkiException("Failed to load from config", e); +// } +// } +// +// /** +// * Creates a new builder to configure instance. +// * +// * @return builder instance +// */ +// public static Builder fullBuilder() { +// return new Builder(); +// } +// +// /** +// * Build this instance from PEM files (usually a pair of private key and certificate chain). +// * Call {@link PemBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for PEM files +// */ +// public static PemBuilder pemBuilder() { +// return new PemBuilder(); +// } +// +// /** +// * Build this instance from a java keystore (such as PKCS12 keystore). +// * Call {@link KeystoreBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for Keystore +// */ +// public static KeystoreBuilder keystoreBuilder() { +// return new KeystoreBuilder(); +// } +// + /** + * The public key of this config if configured. + * + * @return the public key of this config or empty if not configured + */ + /*public*/ Optional publicKey(); +// { +// return Optional.ofNullable(publicKey); +// } + + /** + * The private key of this config if configured. + * + * @return the private key of this config or empty if not configured + */ + /*public*/ Optional privateKey(); +// { +// return Optional.ofNullable(privateKey); +// } + + /** + * The public X.509 Certificate if configured. + * + * @return the public certificate of this config or empty if not configured + */ + /*public*/ Optional publicCert(); +// { +// return Optional.ofNullable(publicCert); +// } + + /** + * The X.509 Certificate Chain. + * + * @return the certificate chain or empty list if not configured + */ + /*public*/ List certChain(); +// { +// return Collections.unmodifiableList(certChain); +// } + + /** + * The X.509 Certificates. + * + * @return the certificates configured or empty list if none configured + */ + /*public*/ List certs(); +// { +// return Collections.unmodifiableList(certificates); +// } + + + /** + * @see FakeKeystoreConfig + */ +// public DefaultFakeConfigBean.Builder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + + +// /** +// * Fluent API builder for {@link FakeKeyConfigBean}. +// * Call {@link #build()} to create an instance. +// * +// * The keys may be loaded from multiple possible sources. +// * +// * @see FakeKeyConfigBean#keystoreBuilder() +// * @see FakeKeyConfigBean#pemBuilder() +// * @see FakeKeyConfigBean#fullBuilder() +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private PrivateKey explicitPrivateKey; +// private PublicKey explicitPublicKey; +// private X509Certificate explicitPublicCert; +// private final List explicitCertChain = new LinkedList<>(); +// private final List explicitCertificates = new LinkedList<>(); +// +// /** +// * Build a new instance of the configuration based on this builder. +// * +// * @return instance from this builder +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// @Override +// public FakeKeyConfigBean build() throws PkiException { +// PrivateKey privateKey = this.explicitPrivateKey; +// PublicKey publicKey = this.explicitPublicKey; +// X509Certificate publicCert = this.explicitPublicCert; +// List certChain = new LinkedList<>(explicitCertChain); +// List certificates = new LinkedList<>(explicitCertificates); +// +// // fix public key if cert is provided +// if (null == publicKey && null != publicCert) { +// publicKey = publicCert.getPublicKey(); +// } +// +// return new FakeKeyConfigBean(privateKey, publicKey, publicCert, certChain, certificates); +// } +// +// /** +// * Configure a private key instance (rather then keystore and alias). +// * +// * @param privateKey private key instance +// * @return updated builder instance +// */ +// public Builder privateKey(PrivateKey privateKey) { +// this.explicitPrivateKey = privateKey; +// return this; +// } +// +// /** +// * Configure a public key instance (rather then keystore and certificate alias). +// * +// * @param publicKey private key instance +// * @return updated builder instance +// */ +// public Builder publicKey(PublicKey publicKey) { +// this.explicitPublicKey = publicKey; +// return this; +// } +// +// /** +// * Configure an X.509 certificate instance for public key certificate. +// * +// * @param certificate certificate instance +// * @return updated builder instance +// */ +// public Builder publicKeyCert(X509Certificate certificate) { +// this.explicitPublicCert = certificate; +// return this; +// } +// +// /** +// * Add an X.509 certificate instance to the end of certification chain. +// * +// * @param certificate certificate to add to certification path +// * @return updated builder instance +// */ +// public Builder addCertChain(X509Certificate certificate) { +// this.explicitCertChain.add(certificate); +// return this; +// } +// +// /** +// * Add a certificate to the list of certificates, used e.g. in a trust store. +// * +// * @param certificate X.509 certificate to trust +// * @return updated builder instance +// */ +// public Builder addCert(X509Certificate certificate) { +// this.explicitCertificates.add(certificate); +// return this; +// } +// +// /** +// * Update this builder with information from a pem builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#pemBuilder()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "pem") +// public Builder updateWith(PemBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Update this builder with information from a keystore builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#keystoreBuilder()} ()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "keystore") +// public Builder updateWith(KeystoreBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Updated this builder instance from configuration. +// * Keys configured will override existing fields in this builder, others will be left intact. +// * If certification path is already defined, configuration based cert-path will be added. +// * +// * @param config configuration to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// updateWith(pemBuilder().config(config)); +// updateWith(keystoreBuilder().config(config)); +// +// return this; +// } +// } +// +// /** +// * Builder for resources from a java keystore (PKCS12, JKS etc.). Obtain an instance through {@link +// * FakeKeyConfigBean#keystoreBuilder()}. +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class KeystoreBuilder implements io.helidon.common.Builder { +// private static final String DEFAULT_KEYSTORE_TYPE = "PKCS12"; +// +// private String keystoreType = DEFAULT_KEYSTORE_TYPE; +// private char[] keystorePassphrase = EMPTY_CHARS; +// private char[] keyPassphrase = null; +// private String keyAlias; +// private String certAlias; +// private String certChainAlias; +// private boolean addAllCertificates; +// private final List certificateAliases = new LinkedList<>(); +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); +// +// private KeystoreBuilder() { +// } +// +// /** +// * If you want to build a trust store, call this method to add all +// * certificates present in the keystore to certificate list. +// * +// * @return updated builder instance +// */ +// @ConfiguredOption(type = Boolean.class, value = "false") +// public KeystoreBuilder trustStore() { +// return trustStore(true); +// } +// +// private KeystoreBuilder trustStore(boolean isTrustStore) { +// this.addAllCertificates = isTrustStore; +// return this; +// } +// +// /** +// * Add an alias to list of aliases used to generate a trusted set of certificates. +// * +// * @param alias alias of a certificate +// * @return updated builder instance +// */ +// public KeystoreBuilder addCertAlias(String alias) { +// certificateAliases.add(alias); +// return this; +// } +// +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// +// /** +// * Set type of keystore. +// * Defaults to "PKCS12", expected are other keystore types supported by java then can store keys under aliases. +// * +// * @param keystoreType keystore type to load the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "type", value = "PKCS12") +// public KeystoreBuilder keystoreType(String keystoreType) { +// this.keystoreType = keystoreType; +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassphrase keystore pass-phrase +// * @return updated builder instance +// */ +// public KeystoreBuilder keystorePassphrase(char[] keystorePassphrase) { +// this.keystorePassphrase = Arrays.copyOf(keystorePassphrase, keystorePassphrase.length); +// +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassword keystore password to use, calls {@link #keystorePassphrase(char[])} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "passphrase") +// public KeystoreBuilder keystorePassphrase(String keystorePassword) { +// return keystorePassphrase(keystorePassword.toCharArray()); +// } +// +// /** +// * Alias of the private key in the keystore. +// * +// * @param keyAlias alias of the key in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.alias", value = "1") +// public KeystoreBuilder keyAlias(String keyAlias) { +// this.keyAlias = keyAlias; +// return this; +// } +// +// /** +// * Alias of X.509 certificate of public key. +// * Used to load both the certificate and public key. +// * +// * @param alias alias under which the certificate is stored in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert.alias") +// public KeystoreBuilder certAlias(String alias) { +// this.certAlias = alias; +// return this; +// } +// +// /** +// * Alias of an X.509 chain. +// * +// * @param alias alias of certificate chain in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.alias") +// public KeystoreBuilder certChainAlias(String alias) { +// this.certChainAlias = alias; +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// public KeystoreBuilder keyPassphrase(char[] privateKeyPassphrase) { +// this.keyPassphrase = Arrays.copyOf(privateKeyPassphrase, privateKeyPassphrase.length); +// +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public KeystoreBuilder keyPassphrase(String privateKeyPassphrase) { +// return keyPassphrase(privateKeyPassphrase.toCharArray()); +// } +// +// /** +// * Create an instance of {@link FakeKeyConfigBean} based on this builder. +// * +// * @return new key config based on a keystore +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Create a builder for {@link FakeKeyConfigBean} from this keystore builder. This allows you to enhance the config +// * with additional (explicit) fields. +// * +// * @return builder of {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// + +// private Builder updateBuilder(Builder builder) { +// if (keystoreStream.isSet()) { +// if (null == keyPassphrase) { +// keyPassphrase = keystorePassphrase; +// } +// KeyStore keyStore; +// +// try { +// keyStore = PkiUtil.loadKeystore(keystoreType, +// keystoreStream.stream(), +// keystorePassphrase, +// keystoreStream.message()); +// } finally { +// keystoreStream.closeStream(); +// } +// +// // attempt to read private key +// boolean guessing = false; +// if (null == keyAlias) { +// keyAlias = DEFAULT_PRIVATE_KEY_ALIAS; +// guessing = true; +// } +// try { +// builder.privateKey(PkiUtil.loadPrivateKey(keyStore, keyAlias, keyPassphrase)); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to read private key from default alias", e); +// } else { +// throw e; +// } +// } +// +// List certChain = null; +// if (null == certChainAlias) { +// guessing = true; +// // by default, cert chain uses the same alias as private key +// certChainAlias = keyAlias; +// } else { +// guessing = false; +// } +// +// if (null != certChainAlias) { +// try { +// certChain = PkiUtil.loadCertChain(keyStore, certChainAlias); +// certChain.forEach(builder::addCertChain); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to certificate chain from alias \"" + certChainAlias + "\"", e); +// } else { +// throw e; +// } +// } +// } +// +// if (null == certAlias) { +// // no explicit public key certificate, just load it from cert chain if present +// if (null != certChain && !certChain.isEmpty()) { +// builder.publicKeyCert(certChain.get(0)); +// } +// } else { +// builder.publicKeyCert(PkiUtil.loadCertificate(keyStore, certAlias)); +// } +// +// if (addAllCertificates) { +// PkiUtil.loadCertificates(keyStore).forEach(builder::addCert); +// } else { +// certificateAliases.forEach(it -> builder.addCert(PkiUtil.loadCertificate(keyStore, it))); +// } +// } +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } +// } +// + +// /** +// * Builder for PEM files - accepts private key and certificate chain. Obtain an instance through {@link +// * FakeKeyConfigBean#pemBuilder()}. +// * +// * If you have "standard" linux/unix private key, you must run " +// * {@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa.p8}" on it to work with this builder for password protected +// * file; or "{@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa_nocrypt.p8 -nocrypt}" for unprotected file. +// * +// * The only supported format is PKCS#8. If you have a different format, you must to transform it to PKCS8 PEM format (to +// * use this builder), or to PKCS#12 keystore format (and use {@link KeystoreBuilder}). +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class PemBuilder implements io.helidon.common.Builder { +// private final StreamHolder privateKeyStream = new StreamHolder("privateKey"); +// private final StreamHolder publicKeyStream = new StreamHolder("publicKey"); +// private final StreamHolder certChainStream = new StreamHolder("certChain"); +// private final StreamHolder certificateStream = new StreamHolder("certificate"); +// private char[] pemKeyPassphrase; +// +// private PemBuilder() { +// } +// +// /** +// * Read a private key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.resource") +// public PemBuilder key(Resource resource) { +// privateKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Read a public key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder publicKey(Resource resource) { +// publicKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// public PemBuilder keyPassphrase(char[] passphrase) { +// this.pemKeyPassphrase = Arrays.copyOf(passphrase, passphrase.length); +// +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public PemBuilder keyPassphrase(String passphrase) { +// return keyPassphrase(passphrase.toCharArray()); +// } +// +// /** +// * Load certificate chain from PEM resource. +// * +// * @param resource resource (e.g. classpath, file path, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.resource") +// public PemBuilder certChain(Resource resource) { +// certChainStream.stream(resource); +// return this; +// } +// +// /** +// * Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder certificates(Resource resource) { +// certificateStream.stream(resource); +// return this; +// } +// +// /** +// * Build {@link FakeKeyConfigBean} based on information from PEM files only. +// * +// * @return new instance configured from this builder +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Get a builder filled from this builder to add additional information (such as public key from certificate etc.). +// * +// * @return builder for {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// +// private Builder updateBuilder(Builder builder) { +// if (privateKeyStream.isSet()) { +// builder.privateKey(PemReader.readPrivateKey(privateKeyStream.stream(), pemKeyPassphrase)); +// } +// if (publicKeyStream.isSet()) { +// builder.publicKey(PemReader.readPublicKey(publicKeyStream.stream())); +// } +// +// if (certChainStream.isSet()) { +// List chain = PemReader.readCertificates(certChainStream.stream()); +// chain.forEach(builder::addCertChain); +// if (!chain.isEmpty()) { +// builder.publicKeyCert(chain.get(0)); +// } +// } +// +// if (certificateStream.isSet()) { +// PemReader.readCertificates(certificateStream.stream()).forEach(builder::addCert); +// } +// +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * Expected keys: +// *
    +// *
  • pem-key-path - path to PEM private key file (PKCS#8 format)
  • +// *
  • pem-key-resource-path - path to resource on classpath
  • +// *
  • pem-key-passphrase - passphrase of private key if encrypted
  • +// *
  • pem-cert-chain-path - path to certificate chain PEM file
  • +// *
  • pem-cert-chain-resource-path - path to resource on classpath
  • +// *
+// * +// * @param config configuration to update builder from +// * @return updated builder instance +// */ +// public PemBuilder config(Config config) { +// Config pemConfig = config.get("pem"); +// pemConfig.get("key.resource").as(Resource::create).ifPresent(this::key); +// pemConfig.get("key.passphrase").asString().map(String::toCharArray).ifPresent(this::keyPassphrase); +// pemConfig.get("cert-chain.resource").as(Resource::create).ifPresent(this::certChain); +// pemConfig.get("certificates.resource").as(Resource::create).ifPresent(this::certificates); +// return this; +// } +// } +// +// private static final class StreamHolder { +// private final String baseMessage; +// private InputStream inputStream; +// private String message; +// +// private StreamHolder(String message) { +// this.baseMessage = message; +// this.message = message; +// } +// +// private boolean isSet() { +// return inputStream != null; +// } +// +// private void stream(Resource resource) { +// closeStream(); +// Objects.requireNonNull(resource, "Resource for \"" + message + "\" must not be null"); +// +// this.inputStream = resource.stream(); +// this.message = message + ":" + resource.sourceType() + ":" + resource.location(); +// } +// +// private InputStream stream() { +// return inputStream; +// } +// +// private String message() { +// return message; +// } +// +// private void closeStream() { +// if (null != inputStream) { +// try { +// inputStream.close(); +// } catch (IOException e) { +// LOGGER.log(Level.WARNING, "Failed to close input stream: " + message, e); +// } +// } +// message = baseMessage; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java new file mode 100644 index 00000000000..bd02e890646 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java @@ -0,0 +1,134 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka KeyConfig.Keystore.Builder + * + * This is a ConfigBean since it marries up to the backing config. + */ +@ConfigBean +public interface FakeKeystoreConfig { + + String DEFAULT_KEYSTORE_TYPE = "PKCS12"; + +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); + +// default FakeKeystoreConfigBean trustStore() { +// return trustStore(true); +// } + + @ConfiguredOption(key = "trust-store") + boolean trustStore(); + +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// default DefaultFakeKeystoreConfigBean.Builder keystore(Resource keystore) { +// +// } + + @ConfiguredOption(key = "type", value = DEFAULT_KEYSTORE_TYPE) + String keystoreType(); + + @ConfiguredOption(key = "passphrase") + char[] keystorePassphrase(); + + @ConfiguredOption(key = "key.alias", value = "1") + String keyAlias(); + + @ConfiguredOption(key = "key.passphrase") + char[] keyPassphrase(); + + @ConfiguredOption(key = "cert.alias") + @Singular("certAlias") + List certAliases(); + + @ConfiguredOption(key = "cert-chain.alias") + String certChainAlias(); + + +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java new file mode 100644 index 00000000000..26809c9d12a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes; + +public enum FakeNettyClientAuth { + NONE, + OPTIONAL, + REQUIRE; + + private FakeNettyClientAuth() { + } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java new file mode 100644 index 00000000000..1f1a094d05a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java @@ -0,0 +1,179 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka PathTracing. + * + * Traced system configuration for web server for a specific path. + */ +@ConfigBean +public interface FakePathTracingConfig { +// /** +// * Create a new traced path configuration from {@link io.helidon.config.Config}. +// * @param config config of a path +// * @return traced path configuration +// */ +// static FakePathTracingConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * Create a new builder to configure traced path configuration. +// * +// * @return a new builder instance +// */ +// static Builder builder() { +// return new Builder(); +// } + + /** + * Path this configuration should configure. + * + * @return path on the web server + */ + String path(); + + /** + * Method(s) this configuration should be valid for. This can be used to restrict the configuration + * only to specific HTTP methods (such as {@code GET} or {@code POST}). + * + * @return list of methods, if empty, this configuration is valid for any method + */ + @Singular("method") // Builder::addMethod(String method); + List methods(); + +// /** +// * Associated configuration of tracing valid for the configured path and (possibly) methods. +// * +// * @return traced system configuration +// */ + @ConfiguredOption(required = true) + FakeTracingConfig tracedConfig(); + +// Optional tracedConfig(); + + +// /** +// * Fluent API builder for {@link FakePathTracingConfigBean}. +// */ +// final class Builder implements io.helidon.common.Builder { +// private final List methods = new LinkedList<>(); +// private String path; +// private TracingConfig tracedConfig; +// +// private Builder() { +// } +// +// @Override +// public FakePathTracingConfigBean build() { +// // immutable +// final String finalPath = path; +// final List finalMethods = new LinkedList<>(methods); +// final TracingConfig finalTracingConfig = tracedConfig; +// +// return new FakePathTracingConfigBean() { +// @Override +// public String path() { +// return finalPath; +// } +// +// @Override +// public List methods() { +// return finalMethods; +// } +// +// @Override +// public TracingConfig tracedConfig() { +// return finalTracingConfig; +// } +// +// @Override +// public String toString() { +// return path + "(" + finalMethods + "): " + finalTracingConfig; +// } +// }; +// } +// +// /** +// * Update this builder from provided {@link io.helidon.config.Config}. +// * +// * @param config config to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// path(config.get("path").asString().get()); +// List methods = config.get("methods").asList(String.class).orElse(null); +// if (null != methods) { +// methods(methods); +// } +// tracingConfig(TracingConfig.create(config)); +// +// return this; +// } +// +// /** +// * Path to register the traced configuration on. +// * +// * @param path path as understood by {@link io.helidon.webserver.Routing.Builder} of web server +// * @return updated builder instance +// */ +// public Builder path(String path) { +// this.path = path; +// return this; +// } +// +// /** +// * HTTP methods to restrict registration of this configuration on web server. +// * @param methods list of methods to use, empty means all methods +// * @return updated builder instance +// */ +// public Builder methods(List methods) { +// this.methods.clear(); +// this.methods.addAll(methods); +// return this; +// } +// +// /** +// * Add a new HTTP method to restrict this configuration for. +// * +// * @param method method to add to the list of supported methods +// * @return updated builder instance +// */ +// public Builder addMethod(String method) { +// this.methods.add(method); +// return this; +// } +// +// /** +// * Configuration of a traced system to use on this path and possibly method(s). +// * +// * @param tracedConfig configuration of components, spans and span logs +// * @return updated builder instance +// */ +// public Builder tracingConfig(TracingConfig tracedConfig) { +// this.tracedConfig = tracedConfig; +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java new file mode 100644 index 00000000000..df7086be20e --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java @@ -0,0 +1,694 @@ +/* + * 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.pico.builder.config.fakes; + +/* + * 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. + */ + +/** + * aka Routing. + */ +public interface FakeRoutingConfig extends FakeServerLifecycle { + +// void route(BareRequest bareRequest, BareResponse bareResponse); +// +// /** +// * Creates new instance of {@link Builder routing builder}. +// * +// * @return a new instance +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * An API to define HTTP request routing rules. +// * +// * @see Builder +// */ +// interface Rules { +// /** +// * Configuration of tracing for this routing. +// * The configuration may control whether to log specific components, +// * spans and span logs, either globally, or for a specific path and method combinations. +// * +// * @param webTracingConfig WebServer tracing configuration +// * @return Updated routing configuration +// */ +// Rules register(WebTracingConfig webTracingConfig); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return Updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(Supplier... serviceBuilders); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(String pathPattern, Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return an updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(String pathPattern, Supplier... serviceBuilders); +// +// /** +// * Routes all GET requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(Handler... requestHandlers); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(String pathPattern, Handler... requestHandlers); +// +// /** +// * Add a route. This allows also protocol version specific routing. +// * +// * @param route route to add +// * @return updated rules +// */ +// Rules route(HttpRoute route); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all PUT requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for a registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all POST requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all RFC 5789 PATCH requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all DELETE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all OPTIONS requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all HEAD requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all TRACE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes requests any specified method to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Registers callback on created new {@link WebServer} instance with this routing. +// * +// * @param webServerConsumer a WebServer creation callback +// * @return updated routing configuration +// */ +// Rules onNewWebServer(Consumer webServerConsumer); +// } +// +// /** +// * A {@link Routing} builder. +// */ +// class Builder implements Rules, io.helidon.common.Builder { +// +// private final RouteListRoutingRules delegate = new RouteListRoutingRules(); +// private final List> errorHandlerRecords = new ArrayList<>(); +// private boolean tracingRegistered; +// +// /** +// * Creates new instance. +// */ +// private Builder() { +// } +// +// // --------------- ROUTING API +// +// @Override +// public Builder register(WebTracingConfig webTracingConfig) { +// this.tracingRegistered = true; +// delegate.register(webTracingConfig); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(Supplier... serviceBuilders) { +// delegate.register(serviceBuilders); +// return this; +// } +// +// @Override +// public Builder register(Service... services) { +// delegate.register(services); +// return this; +// } +// +// @Override +// public Builder register(String pathPattern, Service... services) { +// delegate.register(pathPattern, services); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(String pathPattern, Supplier... serviceBuilders) { +// delegate.register(pathPattern, serviceBuilders); +// return this; +// } +// +// @Override +// public Builder get(Handler... requestHandlers) { +// delegate.get(requestHandlers); +// return this; +// } +// +// @Override +// public Builder get(String pathPattern, Handler... requestHandlers) { +// delegate.get(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder route(HttpRoute route) { +// delegate.register(route); +// return this; +// } +// +// @Override +// public Builder get(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.get(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(Handler... requestHandlers) { +// delegate.put(requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(String pathPattern, Handler... requestHandlers) { +// delegate.put(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.put(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(Handler... requestHandlers) { +// delegate.post(requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(String pathPattern, Handler... requestHandlers) { +// delegate.post(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.post(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(Handler... requestHandlers) { +// delegate.patch(requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(String pathPattern, Handler... requestHandlers) { +// delegate.patch(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.patch(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(Handler... requestHandlers) { +// delegate.delete(requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(String pathPattern, Handler... requestHandlers) { +// delegate.delete(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.delete(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(Handler... requestHandlers) { +// delegate.options(requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(String pathPattern, Handler... requestHandlers) { +// delegate.options(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.options(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(Handler... requestHandlers) { +// delegate.head(requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(String pathPattern, Handler... requestHandlers) { +// delegate.head(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.head(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(Handler... requestHandlers) { +// delegate.trace(requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(String pathPattern, Handler... requestHandlers) { +// delegate.trace(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.trace(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(Handler... requestHandlers) { +// delegate.any(requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(String pathPattern, Handler... requestHandlers) { +// delegate.any(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.any(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, Handler... requestHandlers) { +// delegate.anyOf(methods, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, String pathPattern, Handler... requestHandlers) { +// delegate.anyOf(methods, pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, +// PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.anyOf(methods, pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder onNewWebServer(Consumer webServerConsumer) { +// delegate.onNewWebServer(webServerConsumer); +// return this; +// } +// // --------------- ERROR API +// +// /** +// * Registers an error handler that handles the given type of exceptions. +// * +// * @param exceptionClass the type of exception to handle by this handler +// * @param errorHandler the error handler +// * @param an error handler type +// * @return an updated builder +// */ +// public Builder error(Class exceptionClass, ErrorHandler errorHandler) { +// if (errorHandler == null) { +// return this; +// } +// errorHandlerRecords.add(RequestRouting.ErrorHandlerRecord.of(exceptionClass, errorHandler)); +// +// return this; +// } +// +// // --------------- BUILD API +// +// /** +// * Builds a new routing instance. +// * +// * @return a new instance +// */ +// public Routing build() { +// if (!tracingRegistered) { +// register(WebTracingConfig.create()); +// } +// RouteListRoutingRules.Aggregation aggregate = delegate.aggregate(); +// return new RequestRouting(aggregate.routeList(), errorHandlerRecords, aggregate.newWebServerCallbacks()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java new file mode 100644 index 00000000000..b1099652728 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java @@ -0,0 +1,763 @@ +/* + * 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.pico.builder.config.fakes; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ServerConfiguration. + */ +@ConfigBean +public interface FakeServerConfig extends FakeSocketConfig { + + /** + * Returns the count of threads in the pool used to process HTTP requests. + *

+ * Default value is {@link Runtime#availableProcessors()}. + * + * @return a workers count + */ + int workersCount(); + + /** + * Returns a server port to listen on with the default server socket. If port is + * {@code 0} then any available ephemeral port will be used. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return the server port of the default server socket + */ + @Override + int port(); + +// /** +// * Returns local address where the server listens on with the default server socket. +// * If {@code null} then listens an all local addresses. +// *

+// * Additional named server socket configuration is accessible through +// * the {@link #socket(String)} and {@link #sockets()} methods. +// * +// * @return an address to bind with the default server socket; {@code null} for all local addresses +// */ +// @Override +// InetAddress bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the default server + * socket. + *

+ * Default value is {@link FakeSocketConfig#DEFAULT_BACKLOG_SIZE}. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a maximum length of the queue of incoming connections + */ + @Override + int backlog(); + + /** + * Returns a default server socket timeout in milliseconds or {@code 0} for an infinite timeout. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a default server socket timeout in milliseconds or {@code 0} + */ + @Override + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * default server socket. + *

+ * If {@code 0} then use implementation default. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a buffer size in bytes of the default server socket or {@code 0} + */ + @Override + int receiveBufferSize(); + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code null} if there is no such + * named server socket + * @deprecated since 2.0.0, please use {@link #namedSocket(String)} instead + */ + @Deprecated + default FakeSocketConfig socket(String name) { + return namedSocket(name).orElse(null); + } + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code empty} if there is no such + * named server socket configured + */ + default Optional namedSocket(String name) { + return Optional.ofNullable(sockets().get(name)); + } + + /** + * A map of all the configured server sockets; that is the default server socket + * which is identified by the key {@link io.helidon.pico.config.fake.helidon.WebServer#DEFAULT_SOCKET_NAME} and also all the additional + * named server socket configurations. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @return a map of all the configured server sockets, never null + */ + @Singular("socket") + Map sockets(); + + /** + * The maximum amount of time that the server will wait to shut + * down regardless of the value of any additionally requested + * quiet period. + * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(10L)}.

+ * + * @return the {@link java.time.Duration} to use + */ +// TODO: @DefaultValue (Duration translation) + @ConfiguredOption(key = "whatever") + default Duration maxShutdownTimeout() { + return Duration.ofSeconds(10L); + } + + /** + * The quiet period during which the webserver will wait for new + * incoming connections after it has been told to shut down. + * + *

The webserver will wait no longer than the duration returned + * by the {@link #maxShutdownTimeout()} method.

+ * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(0L)}, indicating + * that there will be no quiet period.

+ * + * @return the {@link java.time.Duration} to use + */ + default Duration shutdownQuietPeriod() { + return Duration.ofSeconds(0L); + } + +// /** +// * Returns a Tracer. +// * +// * @return a tracer to use - never {@code null} +// */ +// Tracer tracer(); + +// /** +// * The top level {@link io.helidon.common.context.Context} to be used by this webserver. +// * @return a context instance with registered application scoped instances +// */ +// Context context(); +// +// /** +// * Returns an optional {@link Transport}. +// * +// * @return an optional {@link Transport} +// */ +// default Optional transport() { +// return Optional.ofNullable(null); +// } + + /** + * Whether to print details of HelidonFeatures. + * + * @return whether to print details + */ + boolean printFeatureDetails(); + +// /** +// * Creates new instance with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new instance +// */ +// static FakeServerConfigBean create(Config config) { +// return builder(config).build(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder}. +// * +// * @return a new builder instance +// * +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()} instead +// */ +// @Deprecated +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder} with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new builder instance +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()}, then +// * {@link WebServer.Builder#config(io.helidon.config.Config)}, or +// * {@link io.helidon.webserver.WebServer#create(Routing, io.helidon.config.Config)} +// */ +// @Deprecated +// static Builder builder(Config config) { +// return new Builder().config(config); +// } +// +// /** +// * A {@link FakeServerConfigBean} builder. +// * +// * @deprecated since 2.0.0 - use {@link io.helidon.webserver.WebServer.Builder} instead +// */ +// @Deprecated +// final class Builder implements FakeSocketConfigBean.SocketConfigurationBuilder, +// io.helidon.common.Builder { +// +// private static final AtomicInteger WEBSERVER_COUNTER = new AtomicInteger(1); +// private final Map socketBuilders = new HashMap<>(); +// private final Map socketsConfigs = new HashMap<>(); +// private int workers; +// private Tracer tracer; +// private Duration maxShutdownTimeout; +// private Duration shutdownQuietPeriod; +// private Optional transport; +// private Context context; +// private boolean printFeatureDetails; +// +// private Builder() { +// transport = Optional.ofNullable(null); +// maxShutdownTimeout = Duration.ofSeconds(10L); +// shutdownQuietPeriod = Duration.ofSeconds(0L); +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContext ssl context +// * @return an updated builder +// */ +// public Builder ssl(SSLContext sslContext) { +// defaultSocketBuilder().ssl(sslContext); +// return this; +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContextBuilder ssl context builder; will be built as a first step of this method execution +// * @return an updated builder +// */ +// public Builder ssl(Supplier sslContextBuilder) { +// defaultSocketBuilder().ssl(sslContextBuilder); +// return this; +// } +// +// /** +// * Sets server port. If port is {@code 0} or less then any available ephemeral port will be used. +// *

+// * Configuration key: {@code port} +// * +// * @param port the server port +// * @return an updated builder +// */ +// public Builder port(int port) { +// defaultSocketBuilder().port(port); +// return this; +// } +// +// /** +// * Sets a local address for server to bind. If {@code null} then listens an all local addresses. +// *

+// * Configuration key: {@code bind-address} +// * +// * @param bindAddress the address to bind the server or {@code null} for all local addresses +// * @return an updated builder +// */ +// public Builder bindAddress(InetAddress bindAddress) { +// defaultSocketBuilder().bindAddress(bindAddress); +// return this; +// } +// +// /** +// * Sets a maximum length of the queue of incoming connections. Default value is {@code 1024}. +// *

+// * Configuration key: {@code backlog} +// * +// * @param size the maximum length of the queue of incoming connections +// * @return an updated builder +// */ +// public Builder backlog(int size) { +// defaultSocketBuilder().backlog(size); +// return this; +// } +// +// /** +// * Sets a socket timeout in milliseconds or {@code 0} for infinite timeout. +// *

+// * Configuration key: {@code timeout} +// * +// * @param milliseconds a socket timeout in milliseconds or {@code 0} +// * @return an updated builder +// */ +// public Builder timeout(int milliseconds) { +// defaultSocketBuilder().timeoutMillis(milliseconds); +// return this; +// } +// +// /** +// * Propose value of the TCP receive window that is advertised to the remote peer. +// * If {@code 0} then implementation default is used. +// *

+// * Configuration key: {@code receive-buffer} +// * +// * @param bytes a buffer size in bytes or {@code 0} +// * @return an updated builder +// */ +// public Builder receiveBufferSize(int bytes) { +// defaultSocketBuilder().receiveBufferSize(bytes); +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// defaultSocketBuilder().maxHeaderSize(size); +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// defaultSocketBuilder().maxInitialLineLength(length); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param port the port to bind; if {@code 0} or less, any available ephemeral port will be used +// * @param bindAddress the address to bind; if {@code null}, all local addresses will be bound +// * @return an updated builder +// * +// * @deprecated since 2.0.0, please use {@link #addSocket(String, FakeSocketConfigBean)} instead +// */ +// @Deprecated +// public Builder addSocket(String name, int port, InetAddress bindAddress) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// return addSocket(name, FakeSocketConfigBean.builder() +// .port(port) +// .bindAddress(bindAddress)); +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketsConfigs.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration builder +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean.Builder socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketBuilders.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration builder. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as +// * a first step of this method execution +// * @return an updated builder +// */ +// public Builder addSocket(String name, Supplier socketConfigurationBuilder) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// +// return addSocket(name, socketConfigurationBuilder != null ? socketConfigurationBuilder.get() : null); +// } +// +// /** +// * Sets a count of threads in pool used to process HTTP requests. +// * Default value is {@code CPU_COUNT * 2}. +// *

+// * Configuration key: {@code workers} +// * +// * @param workers a workers count +// * @return an updated builder +// */ +// public Builder workersCount(int workers) { +// this.workers = workers; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracer a tracer to set +// * @return an updated builder +// */ +// public Builder tracer(Tracer tracer) { +// this.tracer = tracer; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution +// * @return updated builder +// */ +// public Builder tracer(Supplier tracerBuilder) { +// return tracer(tracerBuilder.get()); +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(String... protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(List protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configure maximum client payload size. +// * @param size maximum payload size +// * @return an updated builder +// */ +// @Override +// public Builder maxPayloadSize(long size) { +// defaultSocketBuilder().maxPayloadSize(size); +// return this; +// } +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @Override +// public Builder maxUpgradeContentLength(int size) { +// defaultSocketBuilder().maxUpgradeContentLength(size); +// return this; +// } +// +// /** +// * Configure the maximum amount of time that the server will wait to shut +// * down regardless of the value of any additionally requested +// * quiet period. +// * @param maxShutdownTimeout the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder maxShutdownTimeout(Duration maxShutdownTimeout) { +// this.maxShutdownTimeout = +// Objects.requireNonNull(maxShutdownTimeout, "Parameter 'maxShutdownTimeout' must not be null!"); +// return this; +// } +// +// /** +// * Configure the quiet period during which the webserver will wait for new +// * incoming connections after it has been told to shut down. +// * @param shutdownQuietPeriod the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder shutdownQuietPeriod(Duration shutdownQuietPeriod) { +// this.shutdownQuietPeriod = +// Objects.requireNonNull(shutdownQuietPeriod, "Parameter 'shutdownQuietPeriod' must not be null!"); +// return this; +// } +// +// /** +// * Configure transport. +// * @param transport a {@link Transport} +// * @return an updated builder +// */ +// public Builder transport(Transport transport) { +// this.transport = Optional.of(transport); +// return this; +// } +// +// /** +// * Set to {@code true} to print detailed feature information on startup. +// * +// * @param print whether to print details or not +// * @return updated builder instance +// * @see io.helidon.common.HelidonFeatures +// */ +// public Builder printFeatureDetails(boolean print) { +// this.printFeatureDetails = print; +// return this; +// } +// +// /** +// * Configure the application scoped context to be used as a parent for webserver request contexts. +// * @param context top level context +// * @return an updated builder +// */ +// public Builder context(Context context) { +// this.context = context; +// +// return this; +// } +// +// private InetAddress string2InetAddress(String address) { +// try { +// return InetAddress.getByName(address); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * Sets configuration values included in provided {@link Config} parameter. +// *

+// * It can be used for configuration externalisation. +// *

+// * All parameters sets before this method call can be seen as defaults and all parameters sets after can be seen +// * as forced. +// * +// * @param config the configuration to use +// * @return an updated builder +// */ +// public Builder config(Config config) { +// if (config == null) { +// return this; +// } +// +// defaultSocketBuilder().config(config); +// +// config.get("host").asString().ifPresent(defaultSocketBuilder()::host); +// +// DeprecatedConfig.get(config, "worker-count", "workers") +// .asInt() +// .ifPresent(this::workersCount); +// +// config.get("features.print-details").asBoolean().ifPresent(this::printFeatureDetails); +// +// // shutdown timeouts +// config.get("max-shutdown-timeout-seconds").asLong().ifPresent(it -> maxShutdownTimeout(Duration.ofSeconds(it))); +// config.get("shutdown-quiet-period-seconds").asLong().ifPresent(it -> shutdownQuietPeriod(Duration.ofSeconds(it))); +// +// // sockets +// Config socketsConfig = config.get("sockets"); +// if (socketsConfig.exists()) { +// List socketConfigs = socketsConfig.asNodeList().orElse(List.of()); +// for (Config socketConfig : socketConfigs) { +// // the whole section checking the socket name can be removed +// // when we remove deprecated methods with socket name on server builder +// String socketName; +// +// String nodeName = socketConfig.name(); +// Optional maybeSocketName = socketConfig.get("name").asString().asOptional(); +// +// socketName = maybeSocketName.orElse(nodeName); +// +// // log warning for deprecated config +// try { +// Integer.parseInt(nodeName); +// if (socketName.equals(nodeName) && maybeSocketName.isEmpty()) { +// throw new ConfigException("Cannot find \"name\" key for socket configuration " + socketConfig.key()); +// } +// } catch (NumberFormatException e) { +// // this is old approach +// Logger.getLogger(SocketConfigurationBuilder.class.getName()) +// .warning("Socket configuration at " + socketConfig.key() + " is deprecated. Please use an array " +// + "with \"name\" key to define the socket name."); +// } +// +// FakeSocketConfigBean.Builder socket = FakeSocketConfigBean.builder() +// .name(socketName) +// .config(socketConfig); +// +// socketBuilders.put(socket.name(), socket); +// } +// } +// +// return this; +// } +// +// /** +// * Builds a new configuration instance. +// * +// * @return a new instance +// */ +// @Override +// public FakeServerConfigBean build() { +// if (null == context) { +// // I do not expect "unlimited" number of webservers +// // in case somebody spins a huge number up, the counter will cycle to negative numbers once +// // Integer.MAX_VALUE is reached. +// context = Context.builder() +// .id("web-" + WEBSERVER_COUNTER.getAndIncrement()) +// .build(); +// } +// +// Optional maybeTracer = context.get(Tracer.class); +// +// if (null == this.tracer) { +// this.tracer = maybeTracer.orElseGet(Tracer::global); +// } +// +// if (maybeTracer.isEmpty()) { +// context.register(this.tracer); +// } +// +// if (workers <= 0) { +// workers = Runtime.getRuntime().availableProcessors(); +// } +// +// return new ServerBasicConfig(this); +// } +// +// FakeSocketConfigBean.Builder defaultSocketBuilder() { +// return socketBuilder(WebServer.DEFAULT_SOCKET_NAME); +// } +// +// FakeSocketConfigBean.Builder socketBuilder(String socketName) { +// return socketBuilders.computeIfAbsent(socketName, k -> FakeSocketConfigBean.builder().name(socketName)); +// } +// +// Map sockets() { +// Set builtSocketConfigsKeys = socketsConfigs.keySet(); +// Map result = +// new HashMap<>(this.socketBuilders.size() + this.socketsConfigs.size()); +// for (Map.Entry e : this.socketBuilders.entrySet()) { +// String key = e.getKey(); +// if (builtSocketConfigsKeys.contains(key)) { +// throw new IllegalStateException("Both mutable and immutable socket configuration provided for named socket " +// + key); +// } +// result.put(key, e.getValue().build()); +// } +// +// result.putAll(this.socketsConfigs); +// return result; +// } +// +// int workers() { +// return workers; +// } +// +// Tracer tracer() { +// return tracer; +// } +// +// Duration maxShutdownTimeout() { +// return maxShutdownTimeout; +// } +// +// Duration shutdownQuietPeriod() { +// return shutdownQuietPeriod; +// } +// +// Optional transport() { +// return transport; +// } +// +// Context context() { +// return context; +// } +// +// boolean printFeatureDetails() { +// return printFeatureDetails; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// defaultSocketBuilder().timeout(amount, unit); +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// defaultSocketBuilder().tls(webServerTls); +// return this; +// } +// +// @Override +// public Builder enableCompression(boolean value) { +// defaultSocketBuilder().enableCompression(value); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java new file mode 100644 index 00000000000..e08e34b6093 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java @@ -0,0 +1,37 @@ +/* + * 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.pico.builder.config.fakes; + +/** + * aka ServerLifecycle. + * Basic server lifecycle operations. + */ +public interface FakeServerLifecycle { + +// /** +// * Before server start. +// */ +// default void beforeStart() { +// } +// +// /** +// * After server stop. +// */ +// default void afterStop() { +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java new file mode 100644 index 00000000000..9b7dcb3ba93 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java @@ -0,0 +1,847 @@ +/* + * 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.pico.builder.config.fakes; + +/* + * 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 java.util.Optional; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ServerConfiguration. + * + * The SocketConfiguration configures a port to listen on and its associated server socket parameters. + */ +@ConfigBean +public interface FakeSocketConfig { + + /** + * The default backlog size to configure the server sockets with if no other value + * is provided. + */ + int DEFAULT_BACKLOG_SIZE = 1024; + + /** + * Name of this socket. + * Default to WebServer#DEFAULT_SOCKET_NAME for the main and + * default server socket. All other sockets must be named. + * + * @return name of this socket + */ +// default String name() { +// return WebServer.DEFAULT_SOCKET_NAME; +// } + @ConfiguredOption(WebServer.DEFAULT_SOCKET_NAME) + String name(); + + /** + * Returns a server port to listen on with the server socket. If port is + * {@code 0} then any available ephemeral port will be used. + * + * @return the server port of the server socket + */ + int port(); + +// /** +// * Returns local address where the server listens on with the server socket. +// * If {@code null} then listens an all local addresses. +// * +// * @return an address to bind with the server socket; {@code null} for all local addresses +// */ +// InetAddress bindAddress(); + @ConfiguredOption(key = "bind-address") + String bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the server + * socket. + *

+ * Default value is {@link #DEFAULT_BACKLOG_SIZE}. + * + * @return a maximum length of the queue of incoming connections + */ + @ConfiguredOption("1024") + int backlog(); + + /** + * Returns a server socket timeout in milliseconds or {@code 0} for an infinite timeout. + * + * @return a server socket timeout in milliseconds or {@code 0} + */ + @ConfiguredOption(key = "timeout-millis") + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * server socket. + *

+ * If {@code 0} then use implementation default. + * + * @return a buffer size in bytes of the server socket or {@code 0} + */ + int receiveBufferSize(); + + /** + * Return a {@link FakeWebServerTlsConfig} containing server TLS configuration. When empty {@link java.util.Optional} is returned + * no TLS should be configured. + * + * @return web server tls configuration + */ + Optional tls(); + + /** + * Returns a {@link javax.net.ssl.SSLContext} to use with the server socket. If not {@code null} then + * the server enforces an SSL communication. + * + * @deprecated use {@code tls().sslContext()} instead. This method will be removed at 3.0.0 version. + * @return a SSL context to use + */ + @Deprecated(since = "2.3.1", forRemoval = true) + SSLContext ssl(); + + /** + * Returns the SSL protocols to enable, or {@code null} to enable the default + * protocols. + * @deprecated use {@code tls().enabledTlsProtocols()} instead. This method will be removed at 3.0.0 version. + * @return the SSL protocols to enable + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set enabledSslProtocols(); + + /** + * Return the allowed cipher suite of the TLS. If empty set is returned, the default cipher suite is used. + * + * @deprecated use {@code tls().cipherSuite()} instead. This method will be removed at 3.0.0 version. + * @return the allowed cipher suite + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set allowedCipherSuite(); + + /** + * Whether to require client authentication or not. + * + * @deprecated use {@code tls().clientAuth()} instead. This method will be removed at 3.0.0 version. + * @return client authentication + */ + @Deprecated(since = "2.3.1", forRemoval = true) + FakeNettyClientAuth clientAuth(); + + /** + * Whether this socket is enabled (and will be opened on server startup), or disabled + * (and ignored on server startup). + * + * @return {@code true} for enabled socket, {@code false} for socket that should not be opened + */ +// default boolean enabled() { +// return true; +// } + @ConfiguredOption("true") + boolean enabled(); + + /** + * Maximal size of all headers combined. + * + * @return size in bytes + */ + @ConfiguredOption(key = "max-header-size", value = "8192") + int maxHeaderSize(); + + /** + * Maximal length of the initial HTTP line. + * + * @return length + */ + @ConfiguredOption("4096") + int maxInitialLineLength(); + + /** + * Maximal size of a single chunk of received data. + * + * @return chunk size + */ + int maxChunkSize(); + + /** + * Whether to validate HTTP header names. + * When set to {@code true}, we make sure the header name is a valid string + * + * @return {@code true} if headers should be validated + */ + boolean validateHeaders(); + + /** + * Whether to allow negotiation for a gzip/deflate content encoding. Supporting + * HTTP compression may interfere with application that use streaming and other + * similar features. Thus, it defaults to {@code false}. + * + * @return compression flag + */ +// default boolean enableCompression() { +// return false; +// } + boolean enableCompression(); + + /** + * Maximum size allowed for an HTTP payload in a client request. A negative + * value indicates that there is no maximum set. + * + * @return maximum payload size + */ +// default long maxPayloadSize() { +// return -1L; +// } + @ConfiguredOption("-1") + long maxPayloadSize(); + + /** + * Initial size of the buffer used to parse HTTP line and headers. + * + * @return initial size of the buffer + */ + int initialBufferSize(); + + /** + * Maximum length of the content of an upgrade request. + * + * @return maximum length of the content of an upgrade request + */ +// default int maxUpgradeContentLength() { +// return 64 * 1024; +// } + @ConfiguredOption("65536") + int maxUpgradeContentLength(); + +// /** +// * Creates a builder of {@link FakeSocketConfigBean} class. +// * +// * @return a builder +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create a default named configuration. +// * +// * @param name name of the socket +// * @return a new socket configuration with defaults +// */ +// static FakeSocketConfigBean create(String name) { +// return builder() +// .name(name) +// .build(); +// } +// +// /** +// * Socket configuration builder API, used by {@link io.helidon.webserver.SocketConfiguration.Builder} +// * to configure additional sockets, and by {@link io.helidon.webserver.WebServer.Builder} to +// * configure the default socket. +// * +// * @param type of the subclass of this class to provide correct fluent API +// */ +// @Configured +// interface SocketConfigurationBuilder> { +// /** +// * Configures a server port to listen on with the server socket. If port is +// * {@code 0} then any available ephemeral port will be used. +// * +// * @param port the server port of the server socket +// * @return this builder +// */ +// @ConfiguredOption("0") +// B port(int port); +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param address an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// * @throws io.helidon.config.ConfigException in case the address provided is not a valid host address +// */ +// @ConfiguredOption(deprecated = true) +// default B bindAddress(String address) { +// try { +// return bindAddress(InetAddress.getByName(address)); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * A helper method that just calls {@link #bindAddress(String)}. +// * +// * @param address host to listen on +// * @return this builder +// */ +// @ConfiguredOption +// default B host(String address) { +// return bindAddress(address); +// } +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param bindAddress an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// */ +// B bindAddress(InetAddress bindAddress); +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// @ConfiguredOption("1024") +// B backlog(int backlog); +// +// /** +// * Configures a server socket timeout. +// * +// * @param amount an amount of time to configure the timeout, use {@code 0} for infinite timeout +// * @param unit time unit to use with the configured amount +// * @return this builder +// */ +// @ConfiguredOption(key = "timeout-millis", type = Long.class, value = "0", +// description = "Socket timeout in milliseconds") +// B timeout(long amount, TimeUnit unit); +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @ConfiguredOption +// B receiveBufferSize(int receiveBufferSize); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * If this method is called, any other method except for {@link #tls(java.util.function.Supplier)}¨ +// * and repeated invocation of this method would be ignored. +// *

+// * If this method is called again, the previous configuration would be ignored. +// * +// * @param webServerTls ssl configuration to use with this socket +// * @return this builder +// */ +// @ConfiguredOption +// B tls(FakeWebServerTlsConfigBean webServerTls); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * +// * @param tlsConfig supplier ssl configuration to use with this socket +// * @return this builder +// */ +// default B tls(Supplier tlsConfig) { +// return tls(tlsConfig.get()); +// } +// +// /** +// * Maximal number of bytes of all header values combined. When a bigger value is received, a +// * {@link io.helidon.common.http.Http.Status#BAD_REQUEST_400} +// * is returned. +// *

+// * Default is {@code 8192} +// * +// * @param size maximal number of bytes of combined header values +// * @return this builder +// */ +// @ConfiguredOption("8192") +// B maxHeaderSize(int size); +// +// /** +// * Maximal number of characters in the initial HTTP line. +// *

+// * Default is {@code 4096} +// * +// * @param length maximal number of characters +// * @return this builder +// */ +// @ConfiguredOption("4096") +// B maxInitialLineLength(int length); +// +// /** +// * Enable negotiation for gzip/deflate content encodings. Clients can +// * request compression using the "Accept-Encoding" header. +// *

+// * Default is {@code false} +// * +// * @param value compression flag +// * @return this builder +// */ +// @ConfiguredOption("false") +// B enableCompression(boolean value); +// +// /** +// * Set a maximum payload size for a client request. Can prevent DoS +// * attacks. +// * +// * @param size maximum payload size +// * @return this builder +// */ +// @ConfiguredOption +// B maxPayloadSize(long size); +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @ConfiguredOption("65536") +// B maxUpgradeContentLength(int size); +// +// /** +// * Update this socket configuration from a {@link io.helidon.config.Config}. +// * +// * @param config configuration on the node of a socket +// * @return updated builder instance +// */ +// @SuppressWarnings("unchecked") +// default B config(Config config) { +// config.get("port").asInt().ifPresent(this::port); +// config.get("bind-address").asString().ifPresent(this::host); +// config.get("backlog").asInt().ifPresent(this::backlog); +// config.get("max-header-size").asInt().ifPresent(this::maxHeaderSize); +// config.get("max-initial-line-length").asInt().ifPresent(this::maxInitialLineLength); +// config.get("max-payload-size").asInt().ifPresent(this::maxPayloadSize); +// +// DeprecatedConfig.get(config, "timeout-millis", "timeout") +// .asInt() +// .ifPresent(it -> this.timeout(it, TimeUnit.MILLISECONDS)); +// DeprecatedConfig.get(config, "receive-buffer-size", "receive-buffer") +// .asInt() +// .ifPresent(this::receiveBufferSize); +// +// Optional> enabledProtocols = DeprecatedConfig.get(config, "ssl.protocols", "ssl-protocols") +// .asList(String.class) +// .asOptional(); +// +// // tls +// Config sslConfig = DeprecatedConfig.get(config, "tls", "ssl"); +// if (sslConfig.exists()) { +// try { +// FakeWebServerTlsConfigBean.Builder builder = FakeWebServerTlsConfigBean.builder(); +// enabledProtocols.ifPresent(builder::enabledProtocols); +// builder.config(sslConfig); +// +// this.tls(builder.build()); +// } catch (IllegalStateException e) { +// throw new ConfigException("Cannot load SSL configuration.", e); +// } +// } +// +// // compression +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// return (B) this; +// } +// } +// +// /** +// * The {@link io.helidon.webserver.SocketConfiguration} builder class. +// */ +// @Configured +// final class Builder implements SocketConfigurationBuilder, io.helidon.common.Builder { +// /** +// * @deprecated remove once WebServer.Builder.addSocket(name, socket) methods are removed +// */ +// @Deprecated +// static final String UNCONFIGURED_NAME = "io.helidon.webserver.SocketConfiguration.UNCONFIGURED"; +// private final FakeWebServerTlsConfigBean.Builder tlsConfigBuilder = FakeWebServerTlsConfigBean.builder(); +// +// private int port = 0; +// private InetAddress bindAddress = null; +// private int backlog = DEFAULT_BACKLOG_SIZE; +// private int timeoutMillis = 0; +// private int receiveBufferSize = 0; +// private FakeWebServerTlsConfigBean webServerTls; +// // this is for backward compatibility, should be initialized to null once the +// // methods with `name` are removed from server builder (for adding sockets) +// private String name = UNCONFIGURED_NAME; +// private boolean enabled = true; +// // these values are as defined in Netty implementation +// private int maxHeaderSize = 8192; +// private int maxInitialLineLength = 4096; +// private int maxChunkSize = 8192; +// private boolean validateHeaders = true; +// private int initialBufferSize = 128; +// private boolean enableCompression = false; +// private long maxPayloadSize = -1; +// private int maxUpgradeContentLength = 64 * 1024; +// +// private Builder() { +// } +// +// @Override +// public FakeSocketConfigBean build() { +// if (null == webServerTls) { +// webServerTls = tlsConfigBuilder.build(); +// } +// +// if (null == name) { +// throw new ConfigException("Socket name must be configured for each socket"); +// } +// +// return new ServerBasicConfig.SocketConfig(this); +// } +// +// @Override +// public Builder port(int port) { +// this.port = port; +// return this; +// } +// +// @Override +// public Builder bindAddress(InetAddress bindAddress) { +// this.bindAddress = bindAddress; +// return this; +// } +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// public Builder backlog(int backlog) { +// this.backlog = backlog; +// return this; +// } +// +// /** +// * Configures a server socket timeout in milliseconds or {@code 0} for an infinite timeout. +// * +// * @param timeoutMillis a server socket timeout in milliseconds or {@code 0} +// * @return this builder +// * +// * @deprecated since 2.0.0 please use {@link #timeout(long, java.util.concurrent.TimeUnit)} instead +// */ +// @Deprecated +// public Builder timeoutMillis(int timeoutMillis) { +// this.timeoutMillis = timeoutMillis; +// return this; +// } +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @Override +// public Builder receiveBufferSize(int receiveBufferSize) { +// this.receiveBufferSize = receiveBufferSize; +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContext a SSL context to use +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link #tls(FakeWebServerTlsConfigBean)} instead +// */ +// @Deprecated +// public Builder ssl(SSLContext sslContext) { +// if (null != sslContext) { +// this.tlsConfigBuilder.sslContext(sslContext); +// } +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContextBuilder a SSL context builder to use; will be built as a first step of this +// * method execution +// * @return this builder +// * @deprecated since 2.0.0, please use {@link #tls(Supplier)} instead +// */ +// @Deprecated +// public Builder ssl(Supplier sslContextBuilder) { +// return ssl(sslContextBuilder != null ? sslContextBuilder.get() : null); +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link FakeWebServerTlsConfigBean.Builder#enabledProtocols(String...)} +// * instead +// */ +// @Deprecated +// public Builder enabledSSlProtocols(String... protocols) { +// if (null == protocols) { +// enabledSSlProtocols(List.of()); +// } else { +// enabledSSlProtocols(Arrays.asList(protocols)); +// } +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return this builder +// */ +// @Deprecated +// public Builder enabledSSlProtocols(List protocols) { +// if (null == protocols) { +// this.tlsConfigBuilder.enabledProtocols(List.of()); +// } else { +// this.tlsConfigBuilder.enabledProtocols(protocols); +// } +// return this; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// long timeout = unit.toMillis(amount); +// if (timeout > Integer.MAX_VALUE) { +// this.timeoutMillis = 0; +// } else { +// this.timeoutMillis = (int) timeout; +// } +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// this.webServerTls = webServerTls; +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// this.maxHeaderSize = size; +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// this.maxInitialLineLength = length; +// return this; +// } +// +// @Override +// public Builder maxPayloadSize(long size) { +// this.maxPayloadSize = size; +// return this; +// } +// +// @Override +// public Builder maxUpgradeContentLength(int size) { +// this.maxUpgradeContentLength = size; +// return this; +// } +// +// /** +// * Configure a socket name, to bind named routings to. +// * +// * @param name name of the socket +// * @return updated builder instance +// */ +// @ConfiguredOption(required = true) +// public Builder name(String name) { +// this.name = name; +// return this; +// } +// +// /** +// * Set this socket builder to enabled or disabled. +// * +// * @param enabled when set to {@code false}, the socket is not going to be opened by the server +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// return this; +// } +// +// /** +// * Configure maximal size of a chunk to be read from incoming requests. +// * Defaults to {@code 8192}. +// * +// * @param size maximal chunk size +// * @return updated builder instance +// */ +// public Builder maxChunkSize(int size) { +// this.maxChunkSize = size; +// return this; +// } +// +// /** +// * Configure whether to validate header names. +// * Defaults to {@code true} to make sure header names are valid strings. +// * +// * @param validate set to {@code false} to ignore header validation +// * @return updated builder instance +// */ +// public Builder validateHeaders(boolean validate) { +// this.validateHeaders = validate; +// return this; +// } +// +// /** +// * Configure initial size of the buffer used to parse HTTP line and headers. +// * Defaults to {@code 128}. +// * +// * @param size initial buffer size +// * @return updated builder instance +// */ +// public Builder initialBufferSize(int size) { +// this.initialBufferSize = size; +// return this; +// } +// +// /** +// * Configure whether to enable content negotiation for compression. +// * +// * @param value compression flag +// * @return updated builder instance +// */ +// public Builder enableCompression(boolean value) { +// this.enableCompression = value; +// return this; +// } +// +// @Override +// public Builder config(Config config) { +// SocketConfigurationBuilder.super.config(config); +// +// config.get("name").asString().ifPresent(this::name); +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("max-chunk-size").asInt().ifPresent(this::maxChunkSize); +// config.get("validate-headers").asBoolean().ifPresent(this::validateHeaders); +// config.get("initial-buffer-size").asInt().ifPresent(this::initialBufferSize); +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// +// return this; +// } +// +// int port() { +// return port; +// } +// +// Optional bindAddress() { +// return Optional.ofNullable(bindAddress); +// } +// +// int backlog() { +// return backlog; +// } +// +// int timeoutMillis() { +// return timeoutMillis; +// } +// +// int receiveBufferSize() { +// return receiveBufferSize; +// } +// +// FakeWebServerTlsConfigBean tlsConfig() { +// return webServerTls; +// } +// +// String name() { +// return name; +// } +// +// boolean enabled() { +// return enabled; +// } +// +// int maxHeaderSize() { +// return maxHeaderSize; +// } +// +// int maxInitialLineLength() { +// return maxInitialLineLength; +// } +// +// int maxChunkSize() { +// return maxChunkSize; +// } +// +// boolean validateHeaders() { +// return validateHeaders; +// } +// +// int initialBufferSize() { +// return initialBufferSize; +// } +// +// boolean enableCompression() { +// return enableCompression; +// } +// +// long maxPayloadSize() { +// return maxPayloadSize; +// } +// +// int maxUpgradeContentLength() { +// return maxUpgradeContentLength; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java new file mode 100644 index 00000000000..398d44c44c6 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java @@ -0,0 +1,129 @@ +/* + * 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.pico.builder.config.fakes; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanLogTracingConfig. + * Configuration of a single log event in a traced span. + */ +@ConfigBean +public interface FakeSpanLogTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean DISABLED = FakeSpanLogTracingConfigBean.builder("disabled").enabled(false).build(); +// /** +// * Enabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean ENABLED = FakeSpanLogTracingConfigBean.builder("enabled").build(); +// +// /** +// * A new span log. +// * @param name name of the span log +// */ +// protected FakeSpanLogTracingConfigBean(String name) { +// super(name); +// } +// + +// /** +// * Merge two traced span log configurations. +// * +// * @param older original configuration with default values +// * @param newer new configuration to override the older +// * @return a new traced span log mergint the older and newer +// */ +// static FakeSpanLogTracingConfigBean merge(FakeSpanLogTracingConfigBean older, FakeSpanLogTracingConfigBean newer) { +// return new FakeSpanLogTracingConfigBean(newer.name()) { +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Fluent API builder to create a new traced span log configuration. +// * +// * @param name name of the span log +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced span log configuration from {@link io.helidon.config.Config}. +// * +// * @param name name of the span log +// * @param config config for a traced span log +// * @return a new traced span log configuration +// */ +// public static FakeSpanLogTracingConfigBean create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link FakeSpanLogTracingConfigBean}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final String name; +// private Optional enabled = Optional.empty(); +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public FakeSpanLogTracingConfigBean build() { +// final Optional finalEnabled = enabled; +// return new FakeSpanLogTracingConfigBean(name) { +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Configure whether this traced span log is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config config of a traced span log +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java new file mode 100644 index 00000000000..db45e5b1746 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java @@ -0,0 +1,258 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Map; +import java.util.Optional; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanTracingConfig. + * + * Configuration of a single traced span. + */ +@ConfigBean +public interface FakeSpanTracingConfig extends FakeTraceableConfig { + +// /** +// * A traced span that is disabled and all logs on it are disabled as well. +// */ +// public static final SpanTracingConfig DISABLED = SpanTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * A traced span that is inabled and all logs on it are enabled as well. +// */ +// public static final SpanTracingConfig ENABLED = SpanTracingConfig.builder("enabled").build(); + +// /** +// * A new traceable span. +// * +// * @param name name of this span +// */ +// protected SpanTracingConfig(String name) { +// super(name); +// } +// +// @Override +// public String toString() { +// return "SpanTracingConfig(" + name() + ")"; +// } +// +// /** +// * Merge configuration of two traced spans. +// * +// * @param older older span with default values +// * @param newer newer span overriding values in older +// * @return a new merged traced span configuration +// */ +// static SpanTracingConfig merge(SpanTracingConfig older, SpanTracingConfig newer) { +// return new SpanTracingConfig(newer.name()) { +// @Override +// public Optional newName() { +// return newer.newName() +// .or(older::newName); +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// +// @Override +// public Optional getSpanLog(String name) { +// Optional newLog = newer.getSpanLog(name); +// Optional oldLog = older.getSpanLog(name); +// +// if (newLog.isPresent() && oldLog.isPresent()) { +// return Optional.of(SpanLogTracingConfig.merge(oldLog.get(), newLog.get())); +// } +// +// if (newLog.isPresent()) { +// return newLog; +// } +// +// return oldLog; +// } +// }; +// } + + /** + * When rename is desired, returns the new name. + * + * @return new name for this span or empty when rename is not desired + */ + Optional newName(); + +// /** +// * Configuration of a traced span log. +// * +// * @param name name of the log event +// * @return configuration of the log event, or empty if not explicitly configured (used when merging) +// */ +// protected abstract Optional getSpanLog(String name); + + @Singular("spanLog") // B addSpanLog(String, FakeSpanLogTracingConfigBean); + Map spanLogMap(); + +// /** +// * Configuration of a traceable span log. +// * If this span is disabled, the log is always disabled. +// * +// * @param name name of the log event +// * @return configuration of the log event +// */ +// public final SpanLogTracingConfig spanLog(String name) { +// if (enabled()) { +// return getSpanLog(name).orElse(SpanLogTracingConfig.ENABLED); +// } else { +// return SpanLogTracingConfig.DISABLED; +// } +// } +// +// /** +// * Whether a log event should be logged on the span with a default value. +// * +// * @param logName name of the log event +// * @param defaultValue to use in case the log event is not configured in this span's configuration +// * @return whether to log ({@code true}) the event or not ({@code false}), uses the default value for unconfigured logs +// */ +// public boolean logEnabled(String logName, boolean defaultValue) { +// if (enabled()) { +// return getSpanLog(logName).map(Traceable::enabled).orElse(defaultValue); +// } +// return false; +// } +// +// /** +// * A fluent API builder to create traced span configuration. +// * +// * @param name name of the span +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create traced span configuration from a {@link io.helidon.config.Config}. +// * +// * @param name name of the span +// * @param config config to load span configuration from +// * @return a new traced span configuration +// */ +// public static SpanTracingConfig create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link SpanTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map spanLogMap = new HashMap<>(); +// private final String name; +// private Optional enabled = Optional.empty(); +// private String newName; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public SpanTracingConfig build() { +// final Map finalSpanLogMap = new HashMap<>(spanLogMap); +// final Optional finalNewName = Optional.ofNullable(newName); +// final Optional finalEnabled = enabled; +// +// return new SpanTracingConfig(name) { +// @Override +// public Optional newName() { +// return finalNewName; +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// +// @Override +// protected Optional getSpanLog(String name) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpanLogMap.get(name)); +// } +// return Optional.of(SpanLogTracingConfig.DISABLED); +// } +// }; +// } +// +// /** +// * Configure whether this traced span is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Configure a new name of this span. +// * +// * @param newName new name to use when reporting this span +// * @return updated builder instance +// */ +// public Builder newName(String newName) { +// this.newName = newName; +// return this; +// } +// +// /** +// * Add configuration of a traced span log. +// * +// * @param spanLogTracingConfig configuration of the traced span log +// * @return updated builder instance +// */ +// public Builder addSpanLog(SpanLogTracingConfig spanLogTracingConfig) { +// this.spanLogMap.put(spanLogTracingConfig.name(), spanLogTracingConfig); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of this span +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("new-name").asString().ifPresent(this::newName); +// config.get("logs") +// .asNodeList() +// .ifPresent(nodes -> { +// nodes.forEach(node -> { +// // name is mandatory +// addSpanLog(SpanLogTracingConfig.create(node.get("name").asString().get(), node)); +// }); +// }); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java new file mode 100644 index 00000000000..2a3d4a4e432 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java @@ -0,0 +1,55 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Optional; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka Traceable. + * Tracing configuration that can be enabled or disabled. + */ +@ConfigBean +public interface FakeTraceableConfig { + /** + * Whether this trace should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not, + * {@code empty} when this flag is not explicitly configured + */ + /*protected*/ Optional isEnabled(); + + /** + * Name of this traceable unit. + * + * @return name + */ + String name(); + + /** + * Whether this traceable should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not + */ + default boolean enabled() { + return isEnabled().orElse(true); + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java new file mode 100644 index 00000000000..a431c9d2801 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java @@ -0,0 +1,103 @@ +/* + * 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.pico.builder.config.fakes; + +/** + * Tracer abstraction. + * Tracer is the central point that collects tracing spans, and (probably) pushes them to backend. + */ +public interface FakeTracer { +// /** +// * Create a no-op tracer. All spans created from this tracer are not doing anything. +// * +// * @return no-op tracer +// */ +// static Tracer noOp() { +// return NoOpTracer.instance(); +// } +// +// /** +// * Get the currently registered global tracer. +// * +// * @return global tracer +// */ +// static Tracer global() { +// return TracerProviderHelper.global(); +// } +// +// /** +// * Register a global tracer, behavior depends on implementation. +// * +// * @param tracer tracer to use as a global tracer +// */ +// +// static void global(Tracer tracer) { +// TracerProviderHelper.global(tracer); +// } +// +// /** +// * Whether this tracer is enabled or not. +// * A no op tracer is disabled. +// * +// * @return {@code true} if this tracer is enabled +// */ +// boolean enabled(); +// +// /** +// * A new span builder to construct {@link io.helidon.tracing.Span}. +// * +// * @param name name of the operation +// * @return a new span builder +// */ +// Span.Builder spanBuilder(String name); +// +// /** +// * Extract parent span context from inbound request, such as from HTTP headers. +// * +// * @param headersProvider provider of headers +// * @return span context of inbound parent span, or empty optional if no span context can be found +// */ +// Optional extract(HeaderProvider headersProvider); +// +// /** +// * Inject current span as a parent for outbound request, such as when invoking HTTP request from a client. +// * +// * @param spanContext current span context +// * @param inboundHeadersProvider provider of inbound headers, may be {@link HeaderProvider#empty()} or headers from original +// * request (if any) +// * @param outboundHeadersConsumer consumer of headers that should be propagated to remote endpoint +// */ +// void inject(SpanContext spanContext, HeaderProvider inboundHeadersProvider, HeaderConsumer outboundHeadersConsumer); +// +// /** +// * Access the underlying tracer by specific type. +// * This is a dangerous operation that will succeed only if the tracer is of expected type. This practically +// * removes abstraction capabilities of this API. +// * +// * @param tracerClass type to access +// * @return instance of the tracer +// * @param type of the tracer +// * @throws java.lang.IllegalArgumentException in case the tracer cannot provide the expected type +// */ +// default T unwrap(Class tracerClass) { +// try { +// return tracerClass.cast(this); +// } catch (ClassCastException e) { +// throw new IllegalArgumentException("This tracer is not compatible with " + tracerClass.getName()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java new file mode 100644 index 00000000000..d99c5280f62 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java @@ -0,0 +1,245 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka TracingConfig. + * + * Tracing configuration that contains traced components (such as WebServer, Security) and their traced spans and span logs. + * Spans can be renamed through configuration, components, spans and span logs may be disabled through this configuration. + */ +@ConfigBean(key = "tracing") +public interface FakeTracingConfig extends FakeTraceableConfig { + +// /** +// * Traced config that is enabled for all components, spans and logs. +// */ +// FakeTracingConfig ENABLED = FakeTracingConfig.builder().build(); +// /** +// * Traced conifg that is disabled for all components, spans and logs. +// */ +// FakeTracingConfig DISABLED = FakeTracingConfig.builder().enabled(false).build(); + +// /** +// * A new traced configuration. +// * +// * @param name name of this configuration, when created using {@link FakeTracingConfig.Builder}, +// * the name is {@code helidon} +// */ +// protected FakeTracingConfig(String name) { +// super(name); +// } +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration or empty if defaults should be used +// */ +// protected abstract Optional getComponent(String componentName); +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration if configured, or an enabled component configuration +// */ +// public ComponentTracingConfig component(String componentName) { +// return component(componentName, true); +// } + + @Singular("component") // Builder::addComponent(String component); Impl::getComponent(String component); + Map components(); + +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @param enabledByDefault whether the component should be enabled or disabled in case it is not configured +// * @return component tracing configuration if configured, or an enabled/disabled component configuration depending on +// * {@code enabledByDefault} +// */ +// public ComponentTracingConfig component(String componentName, boolean enabledByDefault) { +// if (enabled()) { +// return getComponent(componentName) +// .orElseGet(() -> enabledByDefault ? ComponentTracingConfig.ENABLED : ComponentTracingConfig.DISABLED); +// } +// +// return ComponentTracingConfig.DISABLED; +// } +// +// @Override +// public String toString() { +// return "TracingConfig(" + name() + ")"; +// } +// +// /** +// * Create new tracing configuration based on the provided config. +// * +// * @param config configuration of tracing +// * @return tracing configuration +// */ +// public static FakeTracingConfig create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * A fluent API builder for tracing configuration. +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Merge two configurations together. +// * The result will combine configuration from both configurations. In case +// * of conflicts, the {@code newer} wins. +// * +// * @param older older instance to merge +// * @param newer newer (more significant) instance to merge +// * @return a new configuration combining odler and newer +// */ +// public static FakeTracingConfig merge(FakeTracingConfig older, FakeTracingConfig newer) { +// return new FakeTracingConfig(newer.name()) { +// @Override +// public Optional getComponent(String componentName) { +// Optional newerComponent = newer.getComponent(componentName); +// Optional olderComponent = older.getComponent(componentName); +// +// // both configured +// if (newerComponent.isPresent() && olderComponent.isPresent()) { +// return Optional.of(ComponentTracingConfig.merge(olderComponent.get(), newerComponent.get())); +// } +// +// // only newer configured +// if (newerComponent.isPresent()) { +// return newerComponent; +// } +// +// // only older configured +// return olderComponent; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Return configuration of a specific span. +// * This is a shortcut method to {@link #component(String)} and +// * {@link ComponentTracingConfig#span(String)}. +// * +// * @param component component, such as "web-server", "security" +// * @param spanName name of the span, such as "HTTP Request", "security:atn" +// * @return configuration of the span if present in this traced system configuration +// */ +// public SpanTracingConfig spanConfig(String component, String spanName) { +// return component(component).span(spanName); +// } + +// /** +// * Fluent API builder for {@link FakeTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map components = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// +// private Builder() { +// } +// +// @Override +// public FakeTracingConfig build() { +// return new RootTracingConfig("helidon", new HashMap<>(components), enabled); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config Config with tracing configuration +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// Config compConfig = config.get("components"); +// compConfig.asNodeList() +// .ifPresent(compList -> { +// compList.forEach(componentConfig -> addComponent(ComponentTracingConfig.create(componentConfig.name(), +// componentConfig))); +// }); +// +// return this; +// } +// +// /** +// * Add a traced component configuration. +// * +// * @param component configuration of this component's tracing +// * @return updated builder instance +// */ +// public Builder addComponent(ComponentTracingConfig component) { +// components.put(component.name(), component); +// return this; +// } +// +// /** +// * Whether overall tracing is enabled. +// * If tracing is disabled on this level, all traced components and spans are disabled - even if explicitly configured +// * as enabled. +// * +// * @param enabled set to {@code false} to disable tracing for any component and span +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +// +// static final class RootTracingConfig extends FakeTracingConfig { +// private final Map components; +// private final Optional enabled; +// +// RootTracingConfig(String name, +// Map components, +// Optional enabled) { +// super(name); +// this.components = components; +// this.enabled = enabled; +// } +// +// @Override +// public Optional getComponent(String componentName) { +// return Optional.ofNullable(components.get(componentName)); +// } +// +// @Override +// public Optional isEnabled() { +// return enabled; +// } +// +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java new file mode 100644 index 00000000000..3b3c7cadd6f --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java @@ -0,0 +1,56 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Objects; +import java.util.Optional; + +import jakarta.annotation.PostConstruct; +import jakarta.inject.Inject; + +//@ConfiguredBy(FakeServerConfig.class) +public class FakeWebServer implements WebServer { + + private FakeServerConfig cfg; + private boolean running; + + @Inject + FakeWebServer(FakeServerConfig cfg, Optional tracer) { + this.cfg = Objects.requireNonNull(cfg); + } + +// /** +// * The traditional approach. +// */ +// FakeWebServer(WebServer.Builder builder) { +// } + + @PostConstruct + public void initialize() { + running = true; + } + + @Override + public FakeServerConfig configuration() { + return cfg; + } + + @Override + public boolean isRunning() { + return running; + } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java new file mode 100644 index 00000000000..55df6d15b72 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java @@ -0,0 +1,437 @@ +/* + * 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.pico.builder.config.fakes; + +import java.security.SecureRandom; +import java.util.Collection; +import java.util.Random; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.common.LazyValue; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka WebServerTls. + * + * A class wrapping transport layer security (TLS) configuration for + * WebServer sockets. + */ +@ConfigBean +public interface FakeWebServerTlsConfig { + String PROTOCOL = "TLS"; + // secure random cannot be stored in native image, it must be initialized at runtime + LazyValue RANDOM = LazyValue.create(SecureRandom::new); + + /** + * This constant is a context classifier for the x509 client certificate if it is present. Callers may use this + * constant to lookup the client certificate associated with the current request context. + */ + String CLIENT_X509_CERTIFICATE = FakeWebServerTlsConfig.class.getName() + ".client-x509-certificate"; + +// private final Set enabledTlsProtocols; +// private final Set cipherSuite; +// private final SSLContext sslContext; +// private final boolean enabled; +// private final ClientAuthentication clientAuth; +// +// private FakeWebServerTlsConfigBean(Builder builder) { +// this.enabledTlsProtocols = Set.copyOf(builder.enabledTlsProtocols); +// this.cipherSuite = builder.cipherSuite; +// this.sslContext = builder.sslContext; +// this.enabled = (null != sslContext); +// this.clientAuth = builder.clientAuth; +// } +// +// /** +// * A fluent API builder for {@link FakeWebServerTlsConfigBean}. +// * +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create TLS configuration from config. +// * +// * @param config located on the node of the tls configuration (usually this is {@code ssl}) +// * @return a new TLS configuration +// */ +// public static FakeWebServerTlsConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// + Collection enabledTlsProtocols(); +// { +// return enabledTlsProtocols; +// } +// + + SSLContext sslContext(); +// { +// return sslContext; +// } + +// ClientAuthentication clientAuth() { +// return clientAuth; +// } + + @Singular("cipher") + Set cipherSuite(); +// { +// return cipherSuite; +// } + + /** + * Whether this TLS config has security enabled (and the socket is going to be + * protected by one of the TLS protocols), or no (and the socket is going to be plain). + * + * @return {@code true} if this configuration represents a TLS configuration, {@code false} for plain configuration + */ + boolean enabled(); +// { +// return enabled; +// } +// +// /** +// * Fluent API builder for {@link FakeWebServerTlsConfigBean}. +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private final Set enabledTlsProtocols = new HashSet<>(); +// +// private SSLContext sslContext; +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeoutSeconds; +// +// private boolean enabled; +// private Boolean explicitEnabled; +// private ClientAuthentication clientAuth; +// private Set cipherSuite = Set.of(); +// +// private Builder() { +// clientAuth = ClientAuthentication.NONE; +// } +// +// @Override +// public FakeWebServerTlsConfigBean build() { +// boolean enabled; +// +// if (null == explicitEnabled) { +// enabled = this.enabled; +// } else { +// enabled = explicitEnabled; +// } +// +// if (!enabled) { +// this.sslContext = null; +// // ssl is disabled +// return new FakeWebServerTlsConfigBean(this); +// } +// +// if (null == sslContext) { +// // no explicit ssl context, build it using private key and trust store +// sslContext = newSSLContext(); +// } +// +// return new FakeWebServerTlsConfigBean(this); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config config on the node of SSL configuration +// * @return this builder +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// if (explicitEnabled != null && !explicitEnabled) { +// return this; +// } +// +// config.get("client-auth").asString().ifPresent(this::clientAuth); +// config.get("private-key") +// .ifExists(it -> privateKey(FakeKeyConfig.create(it))); +// +// config.get("trust") +// .ifExists(it -> trust(FakeKeyConfig.create(it))); +// +// config.get("protocols").asList(String.class).ifPresent(this::enabledProtocols); +// config.get("session-cache-size").asLong().ifPresent(this::sessionCacheSize); +// config.get("cipher-suite").asList(String.class).ifPresent(this::allowedCipherSuite); +// DeprecatedConfig.get(config, "session-timeout-seconds", "session-timeout") +// .asLong() +// .ifPresent(this::sessionTimeoutSeconds); +// +// return this; +// } +// +// private void clientAuth(String it) { +// clientAuth(ClientAuthentication.valueOf(it.toUpperCase())); +// } +// +// /** +// * Configures whether client authentication will be required or not. +// * +// * @param clientAuth client authentication +// * @return this builder +// */ +// @ConfiguredOption("none") +// public Builder clientAuth(ClientAuthentication clientAuth) { +// this.clientAuth = Objects.requireNonNull(clientAuth); +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param context a SSL context to use +// * @return this builder +// */ +// public Builder sslContext(SSLContext context) { +// this.enabled = true; +// this.sslContext = context; +// return this; +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * @param protocols protocols to enable, if empty, enables defaults +// * +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(String... protocols) { +// return enabledProtocols(Arrays.asList(Objects.requireNonNull(protocols))); +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * +// * @param protocols protocols to enable, if empty enables +// * the default protocols +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(Collection protocols) { +// Objects.requireNonNull(protocols); +// +// this.enabledTlsProtocols.clear(); +// this.enabledTlsProtocols.addAll(protocols); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// @ConfiguredOption(required = true) +// public Builder privateKey(FakeKeyConfig privateKeyConfig) { +// // setting private key, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.privateKeyConfig = Objects.requireNonNull(privateKeyConfig); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfigBuilder the required private key configuration parameter +// * @return this builder +// */ +// public Builder privateKey(Supplier privateKeyConfigBuilder) { +// return privateKey(privateKeyConfigBuilder.get()); +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return this builder +// */ +// @ConfiguredOption +// public Builder trust(FakeKeyConfig trustConfig) { +// // setting explicit trust, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.trustConfig = Objects.requireNonNull(trustConfig); +// return this; +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfigBuilder the trust configuration builder +// * @return this builder +// */ +// public Builder trust(Supplier trustConfigBuilder) { +// return trust(trustConfigBuilder.get()); +// } +// +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionTimeoutSeconds(long sessionTimeout) { +// this.sessionTimeoutSeconds = sessionTimeout; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param timeout the session timeout amount +// * @param unit the session timeout time unit +// * @return this builder +// */ +// public Builder sessionTimeout(long timeout, TimeUnit unit) { +// this.sessionTimeoutSeconds = unit.toSeconds(timeout); +// return this; +// } +// +// /** +// * Set allowed cipher suite. If an empty collection is set, an exception is thrown since +// * it is required to support at least some ciphers. +// * +// * @param cipherSuite allowed cipher suite +// * @return an updated builder +// */ +// @ConfiguredOption(key = "cipher-suite") +// public Builder allowedCipherSuite(List cipherSuite) { +// Objects.requireNonNull(cipherSuite); +// if (cipherSuite.isEmpty()) { +// throw new IllegalStateException("Allowed cipher suite has to have at least one cipher specified"); +// } +// this.cipherSuite = Set.copyOf(cipherSuite); +// return this; +// } +// +// /** +// * Whether the TLS config should be enabled or not. +// * +// * @param enabled configure to {@code false} to disable SSL context (and SSL support on the server) +// * @return this builder +// */ +// @ConfiguredOption(description = "Can be used to disable TLS even if keys are configured.", value = "true") +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// this.explicitEnabled = enabled; +// return this; +// } +// +// private SSLContext newSSLContext() { +// try { +// if (null == privateKeyConfig) { +// throw new IllegalStateException("Private key must be configured when SSL is enabled."); +// } +// KeyManagerFactory kmf = buildKmf(this.privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(this.trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (this.sessionTimeoutSeconds > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeoutSeconds, Integer.MAX_VALUE)); +// } +// return ctx; +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Failed to build server SSL Context!", e); +// } +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.get().nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java new file mode 100644 index 00000000000..760b0942b74 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java @@ -0,0 +1,204 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Random; + +import io.helidon.pico.builder.Builder; + +/** + * aka SSLContextBuilder. + * Note that this is just a normal builder, and will not be integrated with Config. + * Builder for configuring a new SslContext for creation. + */ +@Builder +public interface SSLContextConfig { + + String PROTOCOL = "TLS"; + Random RANDOM = new Random(); + +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeout; +// +// private SSLContextConfig() { +// } +// + +// /** +// * Creates a builder of the {@link javax.net.ssl.SSLContext}. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// public static SSLContextConfig create(FakeKeyConfig privateKeyConfig) { +// return new SSLContextConfig().privateKeyConfig(privateKeyConfig); +// } + +// /** +// * Creates {@link javax.net.ssl.SSLContext} from the provided configuration. +// * +// * @param sslConfig the ssl configuration +// * @return a built {@link javax.net.ssl.SSLContext} +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// static SSLContext create(Config sslConfig) { +// return new SSLContextConfig().privateKeyConfig(FakeKeyConfig.create(sslConfig.get("private-key"))) +// .sessionCacheSize(sslConfig.get("session-cache-size").asInt().orElse(0)) +// .sessionTimeout(sslConfig.get("session-timeout").asInt().orElse(0)) +// .trustConfig(FakeKeyConfig.create(sslConfig.get("trust"))) +// .build(); +// } +// +// private SSLContextConfig privateKeyConfig(FakeKeyConfig privateKeyConfig) { +// this.privateKeyConfig = privateKeyConfig; +// return this; +// } + + FakeKeyConfig privateKeyConfig(); + +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return an updated builder +// */ +// public SSLContextConfig trustConfig(FakeKeyConfig trustConfig) { +// this.trustConfig = trustConfig; +// return this; +// } + + FakeKeyConfig trustConfig(); + +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return an updated builder +// */ +// public SSLContextConfig sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } + + long sessionCacheSize(); + +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return an updated builder +// */ +// public SSLContextConfig sessionTimeout(long sessionTimeout) { +// this.sessionTimeout = sessionTimeout; +// return this; +// } + + long sessionTimeout(); + +// /** +// * Create new {@code {@link javax.net.ssl.SSLContext}} instance with configured settings. +// * +// * @return the SSL Context built instance +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// public SSLContext build() { +// Objects.requireNonNull(privateKeyConfig, "The private key config must be set!"); +// +// try { +// return newSSLContext(privateKeyConfig, trustConfig, sessionCacheSize, sessionTimeout); +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Building of the SSLContext of unsuccessful!", e); +// } +// } + + // re-enable this. +// private static SSLContext newSSLContext(FakeKeyConfig privateKeyConfig, +// FakeKeyConfig trustConfig, +// long sessionCacheSize, +// long sessionTimeout) +// throws IOException, GeneralSecurityException { +// KeyManagerFactory kmf = buildKmf(privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (sessionTimeout > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE)); +// } +// return ctx; +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java new file mode 100644 index 00000000000..0da8c238531 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java @@ -0,0 +1,773 @@ +/* + * 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.pico.builder.config.fakes; + +import java.util.Objects; + +import io.helidon.pico.Contract; + +@Contract +public interface WebServer { + + String DEFAULT_SOCKET_NAME = "@default"; + + /** + * Gets effective server configuration. + * + * @return Server configuration + */ + FakeServerConfig configuration(); + +// /** +// * Starts the server. Has no effect if server is running. +// * The start will fail on a server that is shut down, or that failed to start. +// * In such cases, create a new instance of Web Server. +// * +// * @return a single to react on startup process +// */ +// Single start(); +// +// /** +// * Completion stage is completed when server is shut down. +// * +// * @return a completion stage of the server +// */ +// Single whenShutdown(); +// +// /** +// * Attempt to gracefully shutdown server. It is possible to use returned {@link io.helidon.common.reactive.Single} to react. +// *

+// * RequestMethod can be called periodically. +// * +// * @return a single to react on finished shutdown process +// * @see #start() +// */ +// Single shutdown(); + + /** + * Returns {@code true} if the server is currently running. Running server in stopping phase returns {@code true} until it + * is not fully stopped. + * + * @return {@code true} if server is running + */ + boolean isRunning(); + +// /** +// * Gets a {@link WebServer} context. +// * +// * @return a server context +// */ +// Context context(); +// +// /** +// * Get the parent {@link MessageBodyReaderContext} context. +// * +// * @return media body reader context +// */ +// MessageBodyReaderContext readerContext(); +// +// /** +// * Get the parent {@link MessageBodyWriterContext} context. +// * +// * @return media body writer context +// */ +// MessageBodyWriterContext writerContext(); + + /** + * Returns a port number the default server socket is bound to and is listening on; + * or {@code -1} if unknown or not active. + *

+ * It is supported only when server is running. + * + * @return a listen port; or {@code -1} if unknown or the default server socket is not active + */ +// default int port() { +// return port(WebServer.DEFAULT_SOCKET_NAME); +// } + + /** + * Returns a port number an additional named server socket is bound to and is listening on; + * or {@code -1} if unknown or not active. + * + * @param socketName the name of an additional named server socket + * @return a listen port; or {@code -1} if socket name is unknown or the server socket is not active + */ + // based on runtime +// default int port(String socketName) { +// if (!isRunning()) { +// return -1; +// } +// +// FakeSocketConfig cfg = configuration().sockets().get(socketName); +// return (Objects.isNull(cfg)) ? -1 : cfg.port(); +// } + + /** + * Returns {@code true} if TLS is configured for the default socket. + * + * @return whether TLS is enabled for the default socket + */ + default boolean hasTls() { + return hasTls(WebServer.DEFAULT_SOCKET_NAME); + } + + /** + * Returns {@code true} if TLS is configured for the named socket. + * + * @param socketName the name of a socket + * @return whether TLS is enabled for the socket, returns {@code false} if the socket does not exists + */ + default boolean hasTls(String socketName) { + FakeSocketConfig cfg = configuration().sockets().get(socketName); + return !Objects.isNull(cfg) && cfg.tls().isPresent(); + } + +// /** +// * Update the TLS configuration of the default socket {@link WebServer#DEFAULT_SOCKET_NAME}. +// * +// * @param tls new TLS configuration +// * @throws IllegalStateException if {@link WebServerTls#enabled()} returns {@code false} or +// * if {@code SocketConfiguration.tls().sslContext()} returns {@code null} +// */ +// void updateTls(WebServerTls tls); +// +// /** +// * Update the TLS configuration of the named socket. +// * +// * @param tls new TLS configuration +// * @param socketName specific named socket name +// * @throws IllegalStateException if {@link WebServerTls#enabled()} returns {@code false} or +// * if {@code SocketConfiguration.tls().sslContext()} returns {@code null} +// */ +// void updateTls(WebServerTls tls, String socketName); +// +// /** +// * Creates new instance from provided routing and default configuration. +// * +// * @param routing a routing instance +// * @return a new web server instance +// * @throws IllegalStateException if none SPI implementation found +// * @throws NullPointerException if 'routing' parameter is {@code null} +// */ +// static WebServer create(Routing routing) { +// return builder(routing).build(); +// } +// +// /** +// * Creates new instance from provided configuration and routing. +// * +// * @param routing a routing instance +// * @param config configuration located on server configuration node +// * @return a new web server instance +// * @throws NullPointerException if 'routing' parameter is {@code null} +// * +// * @since 2.0.0 +// */ +// static WebServer create(Routing routing, Config config) { +// return builder(routing) +// .config(config) +// .build(); +// } +// +// /** +// * Creates new instance from provided configuration and routing. +// * +// * @param routingBuilder a supplier of routing (such as {@link Routing.Builder} +// * @param config configuration located on server configuration node +// * @return a new web server instance +// * @throws NullPointerException if 'routing' parameter is {@code null} +// * +// * @since 2.0.0 +// */ +// static WebServer create(Supplier routingBuilder, Config config) { +// return builder(routingBuilder.get()) +// .config(config) +// .build(); +// } +// +// /** +// * Creates new instance from provided routing and default configuration. +// * +// * @param routingBuilder a routing builder instance that will be built as a first step +// * of this method execution +// * @return a new web server instance +// * @throws IllegalStateException if none SPI implementation found +// * @throws NullPointerException if 'routing' parameter is {@code null} +// */ +// static WebServer create(Supplier routingBuilder) { +// Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!"); +// return create(routingBuilder.get()); +// } + +// /** +// * Creates a builder of the {@link WebServer}. +// * +// * @param routingBuilder the routing builder; must not be {@code null} +// * @return the builder +// */ +// static Builder builder(Supplier routingBuilder) { +// Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!"); +// return builder(routingBuilder.get()); +// } +// +// /** +// * Creates a fluent API builder of the {@link io.helidon.webserver.WebServer}. +// * Before calling the {@link io.helidon.webserver.WebServer.Builder#build()} method, you should +// * configure the default routing. If none is configured, all requests will end in {@code 404}. +// * +// * @return a new builder +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Creates a builder of the {@link WebServer}. +// * +// * @param routing the routing to use for the default port; must not be {@code null} +// * @return the builder +// * @see #builder() +// */ +// static Builder builder(Routing routing) { +// return builder().addRouting(routing); +// } +// +// /** +// * WebServer builder class provides a convenient way to set up WebServer with multiple server +// * sockets and optional multiple routings. +// */ +// @Configured(root = true, prefix = "server", description = "Configuration of the HTTP server.") +// final class Builder implements io.helidon.common.Builder, +// FakeSocketConfigBean.SocketConfigurationBuilder, +// ParentingMediaContextBuilder, +// MediaContextBuilder { +// +// private static final Logger LOGGER = Logger.getLogger(Builder.class.getName()); +// private static final MediaContext DEFAULT_MEDIA_SUPPORT = MediaContext.create(); +// private final Map routingBuilders = new HashMap<>(); +// private final DirectHandlers.Builder directHandlers = DirectHandlers.builder(); +// // internal use - we may keep this even after we remove the public access to ServerConfiguration +// @SuppressWarnings("deprecation") +// private final FakeServerConfigBean.Builder configurationBuilder = FakeServerConfigBean.builder(); +// // for backward compatibility +// @SuppressWarnings("deprecation") +// private FakeServerConfigBean explicitConfig; +// private MessageBodyReaderContext readerContext; +// private MessageBodyWriterContext writerContext; +// +// private Builder() { +// readerContext = MessageBodyReaderContext.create(DEFAULT_MEDIA_SUPPORT.readerContext()); +// writerContext = MessageBodyWriterContext.create(DEFAULT_MEDIA_SUPPORT.writerContext()); +// } +// +// /** +// * Builds the {@link WebServer} instance as configured by this builder and its parameters. +// * +// * @return a ready to use {@link WebServer} +// * @throws IllegalStateException if there are unpaired named routings (as described +// * at {@link #addNamedRouting(String, Routing)}) +// */ +// @Override +// public WebServer build() { +// if (routingBuilders.get(WebServer.DEFAULT_SOCKET_NAME) == null) { +// LOGGER.warning("Creating a web server with no default routing configured."); +// routingBuilders.put(WebServer.DEFAULT_SOCKET_NAME, RouterImpl.builder()); +// } +// if (explicitConfig == null) { +// explicitConfig = configurationBuilder.build(); +// } +// +// Map routers = routingBuilders.entrySet().stream() +// .collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().build())); +// +// String unpairedRoutings = +// routingBuilders.keySet() +// .stream() +// .filter(routingName -> explicitConfig.namedSocket(routingName).isEmpty()) +// .collect(Collectors.joining(", ")); +// +// if (!unpairedRoutings.isEmpty()) { +// throw new IllegalStateException("No server socket configuration found for named routings: " + unpairedRoutings); +// } +// +// routers.values().forEach(Router::beforeStart); +// +// WebServer result = new NettyWebServer(explicitConfig, +// routers, +// writerContext, +// readerContext, +// directHandlers.build()); +// +// RequestRouting defaultRouting = routers.get(WebServer.DEFAULT_SOCKET_NAME).routing(RequestRouting.class, null); +// +// if (defaultRouting != null) { +// defaultRouting.fireNewWebServer(result); +// } +// return result; +// } +// +// /** +// * Configure listener for the default socket. +// * +// * @param socket socket configuration builder consumer +// * @return updated builder +// */ +// public Builder defaultSocket(Consumer socket){ +// socket.accept(this.configurationBuilder.defaultSocketBuilder()); +// return this; +// } +// +// /** +// * Configure the transport to be used by this server. +// * +// * @param transport transport to use +// * @return updated builder instance +// */ +// public Builder transport(Transport transport) { +// configurationBuilder.transport(transport); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param defaultRouting new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// * @deprecated Use {@link WebServer.Builder#addRouting(Routing)} +// * or {@link WebServer.Builder#addRouting(Routing)} instead. +// */ +// @Deprecated(since = "3.0.0", forRemoval = true) +// public Builder routing(Routing defaultRouting) { +// addRouting(defaultRouting); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param routing new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder addRouting(Routing routing) { +// Objects.requireNonNull(routing); +// routingBuilders.computeIfAbsent(WebServer.DEFAULT_SOCKET_NAME, s -> RouterImpl.builder()) +// .addRouting(routing); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param routingSupplier new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder addRouting(Supplier routingSupplier) { +// Objects.requireNonNull(routingSupplier); +// addRouting(routingSupplier.get()); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param defaultRouting new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder routing(Supplier defaultRouting) { +// addRouting(Objects.requireNonNull(defaultRouting).get()); +// return this; +// } +// +// /** +// * Configure the default routing of this WebServer. Default routing is the one +// * available on the default listen {@link #bindAddress(String) host} and {@link #port() port} of the WebServer +// * +// * @param routing new default routing; if already configured, this instance would replace the existing instance +// * @return updated builder instance +// */ +// public Builder routing(Consumer routing) { +// Routing.Builder builder = Routing.builder(); +// Objects.requireNonNull(routing).accept(builder); +// routingBuilders.computeIfAbsent(WebServer.DEFAULT_SOCKET_NAME, s -> RouterImpl.builder()) +// .addRoutingBuilder(RequestRouting.class, builder); +// return this; +// } +// +// /** +// * Update this server configuration from the config provided. +// * +// * @param config config located on server node +// * @return an updated builder +// * @since 2.0.0 +// */ +// public Builder config(Config config) { +// this.configurationBuilder.config(config); +// return this; +// } +// +// /** +// * Associates a dedicated routing with an additional server socket configuration. +// *

+// * The additional server socket configuration must be set as per +// * {@link io.helidon.pico.config.fake.helidon.config.FakeServerConfigBean.Builder#addSocket(String, io.helidon.pico.config.fake.helidon.config.FakeSocketConfigBean)}. If there is no such +// * named server socket configuration, a {@link IllegalStateException} is thrown by the +// * {@link #build()} method. +// * +// * @param name the named server socket configuration to associate the provided routing with +// * @param routing the routing to associate with the provided name of a named server socket +// * configuration +// * @return an updated builder +// */ +// public Builder addNamedRouting(String name, Routing routing) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// Objects.requireNonNull(routing, "Parameter 'routing' must not be null!"); +// routingBuilders.computeIfAbsent(name, s -> RouterImpl.builder()) +// .addRouting(routing); +// return this; +// } +// +// /** +// * Associates a dedicated routing with an additional server socket configuration. +// *

+// * The additional server socket configuration must be set as per +// * {@link io.helidon.pico.config.fake.helidon.config.FakeServerConfigBean.Builder#addSocket(String, io.helidon.pico.config.fake.helidon.config.FakeSocketConfigBean)}. If there is no such +// * named server socket configuration, a {@link IllegalStateException} is thrown by the +// * {@link #build()} method. +// * +// * @param name the named server socket configuration to associate the provided routing with +// * @param routingBuilder the routing builder to associate with the provided name of a named server socket +// * configuration; will be built as a first step of this method execution +// * @return an updated builder +// */ +// public Builder addNamedRouting(String name, Supplier routingBuilder) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!"); +// +// return addNamedRouting(name, routingBuilder.get()); +// } +// +// @Override +// public Builder mediaContext(MediaContext mediaContext) { +// Objects.requireNonNull(mediaContext); +// this.readerContext = MessageBodyReaderContext.create(mediaContext.readerContext()); +// this.writerContext = MessageBodyWriterContext.create(mediaContext.writerContext()); +// return this; +// } +// +// @Override +// public Builder addMediaSupport(MediaSupport mediaSupport) { +// Objects.requireNonNull(mediaSupport); +// mediaSupport.register(readerContext, writerContext); +// return this; +// } +// +// @Override +// public Builder addReader(MessageBodyReader reader) { +// readerContext.registerReader(reader); +// return this; +// } +// +// @Override +// public Builder addStreamReader(MessageBodyStreamReader streamReader) { +// readerContext.registerReader(streamReader); +// return this; +// } +// +// @Override +// public Builder addWriter(MessageBodyWriter writer) { +// writerContext.registerWriter(writer); +// return this; +// } +// +// @Override +// public Builder addStreamWriter(MessageBodyStreamWriter streamWriter) { +// writerContext.registerWriter(streamWriter); +// return this; +// } +// +// @Override +// public Builder port(int port) { +// configurationBuilder.port(port); +// return this; +// } +// +// @Override +// public Builder bindAddress(InetAddress bindAddress) { +// configurationBuilder.bindAddress(bindAddress); +// return this; +// } +// +// @Override +// public Builder backlog(int backlog) { +// configurationBuilder.backlog(backlog); +// return this; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// configurationBuilder.timeout(amount, unit); +// return this; +// } +// +// @Override +// public Builder receiveBufferSize(int receiveBufferSize) { +// configurationBuilder.receiveBufferSize(receiveBufferSize); +// return this; +// } +// +// @Override +// public Builder tls(WebServerTls webServerTls) { +// configurationBuilder.tls(webServerTls); +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// configurationBuilder.maxHeaderSize(size); +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// configurationBuilder.maxInitialLineLength(length); +// return this; +// } +// +// @Override +// public Builder enableCompression(boolean value) { +// configurationBuilder.enableCompression(value); +// return this; +// } +// +// @Override +// public Builder maxPayloadSize(long size) { +// configurationBuilder.maxPayloadSize(size); +// return this; +// } +// +// @Override +// public Builder maxUpgradeContentLength(int size) { +// configurationBuilder.maxUpgradeContentLength(size); +// return this; +// } +// +// /** +// * A helper method to support fluentAPI when invoking another method. +// *

+// * Example: +// *

+//         *     WebServer.Builder builder = WebServer.builder();
+//         *     updateBuilder(builder);
+//         *     return builder.build();
+//         * 
+// * Can be changed to: +// *
+//         *     return WebServer.builder()
+//         *              .update(this::updateBuilder)
+//         *              .build();
+//         * 
+// * +// * +// * @param updateFunction function to update this builder +// * @return an updated builder +// */ +// public Builder update(Consumer updateFunction) { +// updateFunction.accept(this); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param config the additional named server socket configuration, never null +// * @return an updated builder +// */ +// @ConfiguredOption(key = "sockets", kind = ConfiguredOption.Kind.LIST) +// public Builder addSocket(FakeSocketConfigBean config) { +// configurationBuilder.addSocket(config.name(), config); +// return this; +// } +// +// /** +// * Adds or augment existing named server socket configuration. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name socket name +// * @param socket new or existing configuration builder +// * @return an updated builder +// */ +// public Builder socket(String name, Consumer socket) { +// socket.accept(configurationBuilder.socketBuilder(name)); +// return this; +// } +// +// /** +// * Adds or augment existing named server socket configuration. +// *

+// * An additional named server socket have a dedicated {@link Routing} configured +// * through supplied routing builder. +// * +// * @param socketName socket name +// * @param builders consumer with socket configuration and dedicated routing builders +// * @return an updated builder +// */ +// public Builder socket(String socketName, BiConsumer builders) { +// builders.accept( +// this.configurationBuilder.socketBuilder(socketName), +// routingBuilders.computeIfAbsent(socketName, s -> RouterImpl.builder()) +// ); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration builder. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as +// * a first step of this method execution +// * @return an updated builder +// */ +// public Builder addSocket(Supplier socketConfigurationBuilder) { +// FakeSocketConfigBean socketConfiguration = socketConfigurationBuilder.get(); +// +// configurationBuilder.addSocket(socketConfiguration.name(), socketConfiguration); +// return this; +// } +// +// /** +// * Add a named socket and routing. +// * +// * @param socketConfiguration named configuration of the socket +// * @param routing routing to use for this socket +// * +// * @return an updated builder +// */ +// public Builder addSocket(FakeSocketConfigBean socketConfiguration, Routing routing) { +// addSocket(socketConfiguration); +// addNamedRouting(socketConfiguration.name(), routing); +// return this; +// } +// +// +// /** +// * Sets a tracer. +// * +// * @param tracer a tracer to set +// * @return an updated builder +// */ +// public Builder tracer(Tracer tracer) { +// configurationBuilder.tracer(tracer); +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution +// * @return updated builder +// */ +// public Builder tracer(Supplier tracerBuilder) { +// configurationBuilder.tracer(tracerBuilder); +// return this; +// } +// +// /** +// * A method to validate a named socket configuration exists in this builder. +// * +// * @param socketName name of the socket, using {@link io.helidon.webserver.WebServer#DEFAULT_SOCKET_NAME} +// * will always return {@code true} +// * @return {@code true} in case the named socket is configured in this builder +// */ +// public boolean hasSocket(String socketName) { +// return DEFAULT_SOCKET_NAME.equals(socketName) +// || configurationBuilder.sockets().containsKey(socketName); +// } +// +// /** +// * Configure the application scoped context to be used as a parent for webserver request contexts. +// * @param context top level context +// * @return an updated builder +// */ +// public Builder context(Context context) { +// configurationBuilder.context(context); +// return this; +// } +// +// /** +// * Sets a count of threads in pool used to process HTTP requests. +// * Default value is {@code CPU_COUNT * 2}. +// *

+// * Configuration key: {@code workers} +// * +// * @param workers a workers count +// * @return an updated builder +// */ +// @ConfiguredOption(key = "worker-count") +// public Builder workersCount(int workers) { +// configurationBuilder.workersCount(workers); +// return this; +// } +// +// /** +// * Set to {@code true} to print detailed feature information on startup. +// * +// * @param shouldPrint whether to print details or not +// * @return updated builder instance +// * @see io.helidon.common.HelidonFeatures +// */ +// @ConfiguredOption(key = "features.print-details", value = "false") +// public Builder printFeatureDetails(boolean shouldPrint) { +// configurationBuilder.printFeatureDetails(shouldPrint); +// return this; +// } +// +// /** +// * Provide a custom handler for events that bypass routing. +// * The handler can customize status, headers and message. +// *

+// * Examples of bad request ({@link DirectHandler.EventType#BAD_REQUEST}: +// *

    +// *
  • Invalid character in path
  • +// *
  • Content-Length header set to a non-integer value
  • +// *
  • Invalid first line of the HTTP request
  • +// *
+// * @param handler direct handler to use +// * @param types event types to handle with the provided handler +// * @return updated builder +// */ +// public Builder directHandler(DirectHandler handler, DirectHandler.EventType... types) { +// for (DirectHandler.EventType type : types) { +// directHandlers.addHandler(type, handler); +// } +// +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java new file mode 100644 index 00000000000..1f6fb1a11a7 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes.config; + +/** + * Indicates whether the server requires authentication of tbe client by the certificate. + */ +public enum FakeClientAuth { + + /** + * Authentication is required. + */ + REQUIRE(FakeNettyClientAuth.REQUIRE), + + /** + * Authentication is optional. + */ + OPTIONAL(FakeNettyClientAuth.OPTIONAL), + + /** + * Authentication is not required. + */ + NONE(FakeNettyClientAuth.NONE); + + private final FakeNettyClientAuth clientAuth; + + FakeClientAuth(FakeNettyClientAuth clientAuth) { + this.clientAuth = clientAuth; + } + + FakeNettyClientAuth nettyClientAuth(){ + return clientAuth; + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java new file mode 100644 index 00000000000..182690407bc --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java @@ -0,0 +1,223 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ComponentTracing. + */ +@ConfigBean +public interface FakeComponentTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled component - all subsequent calls return disabled spans and logs. +// */ +// public static final ComponentTracingConfig DISABLED = ComponentTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * Enabled component - all subsequent calls return enabled spans and logs. +// */ +// public static final ComponentTracingConfig ENABLED = ComponentTracingConfig.builder("enabled").build(); + +// /** +// * A new named component. +// * +// * @param name name of the component +// */ +// protected ComponentTracingConfig(String name) { +// super(name); +// } +// + +// /** +// * Merge configuration of two traced components. This enabled hierarchical configuration +// * with common, default configuration in one traced component and override in another. +// * +// * @param older the older configuration with "defaults" +// * @param newer the newer configuration to override defaults in older +// * @return merged component +// */ +// static ComponentTracingConfig merge(ComponentTracingConfig older, ComponentTracingConfig newer) { +// return new ComponentTracingConfig(newer.name()) { +// @Override +// public Optional getSpan(String spanName) { +// if (!enabled()) { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// +// Optional newSpan = newer.getSpan(spanName); +// Optional oldSpan = older.getSpan(spanName); +// +// // both configured +// if (newSpan.isPresent() && oldSpan.isPresent()) { +// return Optional.of(SpanTracingConfig.merge(oldSpan.get(), newSpan.get())); +// } +// +// // only newer +// if (newSpan.isPresent()) { +// return newSpan; +// } +// +// return oldSpan; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of the span in this component +// * @return configuration of that span if present +// */ +// protected abstract Optional getSpan(String spanName); +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @return configuration of the span, or enabled configuration if not configured +// * @see #span(String, boolean) +// */ +// public SpanTracingConfig span(String spanName) { +// return span(spanName, true); +// } + + @Singular("span") // Builder::addSpan(String span, FakeSpanLogTracingConfigBean val), Impl::getSpan(String span), etc. + Map spanLogMap(); + +// +// /** +// * Get a traced span configuration for a named span. +// * +// * @param spanName name of a span in this component +// * @param enabledByDefault whether the result is enabled if a configuration is not present +// * @return configuration of the span, or a span configuration enabled or disabled depending on {@code enabledByDefault} if +// * not configured +// */ +// public SpanTracingConfig span(String spanName, boolean enabledByDefault) { +// if (enabled()) { +// return getSpan(spanName).orElseGet(() -> enabledByDefault ? SpanTracingConfig.ENABLED : SpanTracingConfig.DISABLED); +// } +// +// return SpanTracingConfig.DISABLED; +// } +// +// /** +// * Fluent API builder for traced component. +// * +// * @param name the name of the component +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced component configuration from {@link Config}. +// * +// * @param name name of the component +// * @param config config for a new component +// * @return a new traced component configuration +// */ +// public static ComponentTracingConfig create(String name, Config config) { +// return builder(name) +// .config(config) +// .build(); +// } +// +// /** +// * Fluent API builder for {@link ComponentTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map tracedSpans = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// private final String name; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public ComponentTracingConfig build() { +// // immutability +// final Optional finalEnabled = enabled; +// final Map finalSpans = new HashMap<>(tracedSpans); +// return new ComponentTracingConfig(name) { +// @Override +// public Optional getSpan(String spanName) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpans.get(spanName)); +// } else { +// return Optional.of(SpanTracingConfig.DISABLED); +// } +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of a traced component +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("spans").asNodeList().ifPresent(spanConfigList -> { +// spanConfigList.forEach(spanConfig -> { +// // span name is mandatory +// addSpan(SpanTracingConfig.create(spanConfig.get("name").asString().get(), spanConfig)); +// }); +// }); +// return this; +// } +// +// /** +// * Add a new traced span configuration. +// * +// * @param span configuration of a traced span +// * @return updated builder instance +// */ +// public Builder addSpan(SpanTracingConfig span) { +// this.tracedSpans.put(span.name(), span); +// return this; +// } +// +// /** +// * Configure whether this component is enabled or disabled. +// * +// * @param enabled if disabled, all spans and logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java new file mode 100644 index 00000000000..3adb14006fc --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java @@ -0,0 +1,839 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Optional; + +import io.helidon.pico.builder.Builder; + +/** + * aka KeyConfig. + * + */ +@Builder +public interface FakeKeyConfig { + + // /*private static final*/ String DEFAULT_PRIVATE_KEY_ALIAS = "1"; +// /*private static final*/ char[] EMPTY_CHARS = new char[0]; + +// private static final Logger LOGGER = Logger.getLogger(FakeKeyConfigBean.class.getName()); +// +// private final PrivateKey privateKey; +// private final PublicKey publicKey; +// private final X509Certificate publicCert; +// private final List certChain = new LinkedList<>(); +// private final List certificates = new LinkedList<>(); +// +// private FakeKeyConfigBean(PrivateKey privateKey, +// PublicKey publicKey, +// X509Certificate publicCert, +// Collection certChain, +// Collection certificates) { +// +// this.privateKey = privateKey; +// this.publicKey = publicKey; +// this.publicCert = publicCert; +// this.certChain.addAll(certChain); +// this.certificates.addAll(certificates); +// } +// +// /** +// * Load key config from config. +// * +// * @param config config instance located at keys configuration (expects "keystore-path" child) +// * @return KeyConfig loaded from config +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// public static FakeKeyConfigBean create(Config config) throws PkiException { +// try { +// return fullBuilder().config(config).build(); +// } catch (ResourceException e) { +// throw new PkiException("Failed to load from config", e); +// } +// } +// +// /** +// * Creates a new builder to configure instance. +// * +// * @return builder instance +// */ +// public static Builder fullBuilder() { +// return new Builder(); +// } +// +// /** +// * Build this instance from PEM files (usually a pair of private key and certificate chain). +// * Call {@link PemBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for PEM files +// */ +// public static PemBuilder pemBuilder() { +// return new PemBuilder(); +// } +// +// /** +// * Build this instance from a java keystore (such as PKCS12 keystore). +// * Call {@link KeystoreBuilder#build()} to build the instance. +// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. +// * +// * @return builder for Keystore +// */ +// public static KeystoreBuilder keystoreBuilder() { +// return new KeystoreBuilder(); +// } +// + /** + * The public key of this config if configured. + * + * @return the public key of this config or empty if not configured + */ + /*public*/ Optional publicKey(); +// { +// return Optional.ofNullable(publicKey); +// } + + /** + * The private key of this config if configured. + * + * @return the private key of this config or empty if not configured + */ + /*public*/ Optional privateKey(); +// { +// return Optional.ofNullable(privateKey); +// } + + /** + * The public X.509 Certificate if configured. + * + * @return the public certificate of this config or empty if not configured + */ + /*public*/ Optional publicCert(); +// { +// return Optional.ofNullable(publicCert); +// } + + /** + * The X.509 Certificate Chain. + * + * @return the certificate chain or empty list if not configured + */ + /*public*/ List certChain(); +// { +// return Collections.unmodifiableList(certChain); +// } + + /** + * The X.509 Certificates. + * + * @return the certificates configured or empty list if none configured + */ + /*public*/ List certs(); +// { +// return Collections.unmodifiableList(certificates); +// } + + +// public DefaultFakeConfigBean.Builder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + + +// /** +// * Fluent API builder for {@link FakeKeyConfigBean}. +// * Call {@link #build()} to create an instance. +// * +// * The keys may be loaded from multiple possible sources. +// * +// * @see FakeKeyConfigBean#keystoreBuilder() +// * @see FakeKeyConfigBean#pemBuilder() +// * @see FakeKeyConfigBean#fullBuilder() +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private PrivateKey explicitPrivateKey; +// private PublicKey explicitPublicKey; +// private X509Certificate explicitPublicCert; +// private final List explicitCertChain = new LinkedList<>(); +// private final List explicitCertificates = new LinkedList<>(); +// +// /** +// * Build a new instance of the configuration based on this builder. +// * +// * @return instance from this builder +// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured +// */ +// @Override +// public FakeKeyConfigBean build() throws PkiException { +// PrivateKey privateKey = this.explicitPrivateKey; +// PublicKey publicKey = this.explicitPublicKey; +// X509Certificate publicCert = this.explicitPublicCert; +// List certChain = new LinkedList<>(explicitCertChain); +// List certificates = new LinkedList<>(explicitCertificates); +// +// // fix public key if cert is provided +// if (null == publicKey && null != publicCert) { +// publicKey = publicCert.getPublicKey(); +// } +// +// return new FakeKeyConfigBean(privateKey, publicKey, publicCert, certChain, certificates); +// } +// +// /** +// * Configure a private key instance (rather then keystore and alias). +// * +// * @param privateKey private key instance +// * @return updated builder instance +// */ +// public Builder privateKey(PrivateKey privateKey) { +// this.explicitPrivateKey = privateKey; +// return this; +// } +// +// /** +// * Configure a public key instance (rather then keystore and certificate alias). +// * +// * @param publicKey private key instance +// * @return updated builder instance +// */ +// public Builder publicKey(PublicKey publicKey) { +// this.explicitPublicKey = publicKey; +// return this; +// } +// +// /** +// * Configure an X.509 certificate instance for public key certificate. +// * +// * @param certificate certificate instance +// * @return updated builder instance +// */ +// public Builder publicKeyCert(X509Certificate certificate) { +// this.explicitPublicCert = certificate; +// return this; +// } +// +// /** +// * Add an X.509 certificate instance to the end of certification chain. +// * +// * @param certificate certificate to add to certification path +// * @return updated builder instance +// */ +// public Builder addCertChain(X509Certificate certificate) { +// this.explicitCertChain.add(certificate); +// return this; +// } +// +// /** +// * Add a certificate to the list of certificates, used e.g. in a trust store. +// * +// * @param certificate X.509 certificate to trust +// * @return updated builder instance +// */ +// public Builder addCert(X509Certificate certificate) { +// this.explicitCertificates.add(certificate); +// return this; +// } +// +// /** +// * Update this builder with information from a pem builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#pemBuilder()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "pem") +// public Builder updateWith(PemBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Update this builder with information from a keystore builder. +// * +// * @param builder builder obtained from {@link FakeKeyConfigBean#keystoreBuilder()} ()} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "keystore") +// public Builder updateWith(KeystoreBuilder builder) { +// builder.updateBuilder(this); +// return this; +// } +// +// /** +// * Updated this builder instance from configuration. +// * Keys configured will override existing fields in this builder, others will be left intact. +// * If certification path is already defined, configuration based cert-path will be added. +// * +// * @param config configuration to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// updateWith(pemBuilder().config(config)); +// updateWith(keystoreBuilder().config(config)); +// +// return this; +// } +// } +// +// /** +// * Builder for resources from a java keystore (PKCS12, JKS etc.). Obtain an instance through {@link +// * FakeKeyConfigBean#keystoreBuilder()}. +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class KeystoreBuilder implements io.helidon.common.Builder { +// private static final String DEFAULT_KEYSTORE_TYPE = "PKCS12"; +// +// private String keystoreType = DEFAULT_KEYSTORE_TYPE; +// private char[] keystorePassphrase = EMPTY_CHARS; +// private char[] keyPassphrase = null; +// private String keyAlias; +// private String certAlias; +// private String certChainAlias; +// private boolean addAllCertificates; +// private final List certificateAliases = new LinkedList<>(); +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); +// +// private KeystoreBuilder() { +// } +// +// /** +// * If you want to build a trust store, call this method to add all +// * certificates present in the keystore to certificate list. +// * +// * @return updated builder instance +// */ +// @ConfiguredOption(type = Boolean.class, value = "false") +// public KeystoreBuilder trustStore() { +// return trustStore(true); +// } +// +// private KeystoreBuilder trustStore(boolean isTrustStore) { +// this.addAllCertificates = isTrustStore; +// return this; +// } +// +// /** +// * Add an alias to list of aliases used to generate a trusted set of certificates. +// * +// * @param alias alias of a certificate +// * @return updated builder instance +// */ +// public KeystoreBuilder addCertAlias(String alias) { +// certificateAliases.add(alias); +// return this; +// } +// +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// +// /** +// * Set type of keystore. +// * Defaults to "PKCS12", expected are other keystore types supported by java then can store keys under aliases. +// * +// * @param keystoreType keystore type to load the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "type", value = "PKCS12") +// public KeystoreBuilder keystoreType(String keystoreType) { +// this.keystoreType = keystoreType; +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassphrase keystore pass-phrase +// * @return updated builder instance +// */ +// public KeystoreBuilder keystorePassphrase(char[] keystorePassphrase) { +// this.keystorePassphrase = Arrays.copyOf(keystorePassphrase, keystorePassphrase.length); +// +// return this; +// } +// +// /** +// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). +// * +// * @param keystorePassword keystore password to use, calls {@link #keystorePassphrase(char[])} +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "passphrase") +// public KeystoreBuilder keystorePassphrase(String keystorePassword) { +// return keystorePassphrase(keystorePassword.toCharArray()); +// } +// +// /** +// * Alias of the private key in the keystore. +// * +// * @param keyAlias alias of the key in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.alias", value = "1") +// public KeystoreBuilder keyAlias(String keyAlias) { +// this.keyAlias = keyAlias; +// return this; +// } +// +// /** +// * Alias of X.509 certificate of public key. +// * Used to load both the certificate and public key. +// * +// * @param alias alias under which the certificate is stored in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert.alias") +// public KeystoreBuilder certAlias(String alias) { +// this.certAlias = alias; +// return this; +// } +// +// /** +// * Alias of an X.509 chain. +// * +// * @param alias alias of certificate chain in the keystore +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.alias") +// public KeystoreBuilder certChainAlias(String alias) { +// this.certChainAlias = alias; +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// public KeystoreBuilder keyPassphrase(char[] privateKeyPassphrase) { +// this.keyPassphrase = Arrays.copyOf(privateKeyPassphrase, privateKeyPassphrase.length); +// +// return this; +// } +// +// /** +// * 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. +// * +// * @param privateKeyPassphrase pass-phrase of the key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public KeystoreBuilder keyPassphrase(String privateKeyPassphrase) { +// return keyPassphrase(privateKeyPassphrase.toCharArray()); +// } +// +// /** +// * Create an instance of {@link FakeKeyConfigBean} based on this builder. +// * +// * @return new key config based on a keystore +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Create a builder for {@link FakeKeyConfigBean} from this keystore builder. This allows you to enhance the config +// * with additional (explicit) fields. +// * +// * @return builder of {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// + +// private Builder updateBuilder(Builder builder) { +// if (keystoreStream.isSet()) { +// if (null == keyPassphrase) { +// keyPassphrase = keystorePassphrase; +// } +// KeyStore keyStore; +// +// try { +// keyStore = PkiUtil.loadKeystore(keystoreType, +// keystoreStream.stream(), +// keystorePassphrase, +// keystoreStream.message()); +// } finally { +// keystoreStream.closeStream(); +// } +// +// // attempt to read private key +// boolean guessing = false; +// if (null == keyAlias) { +// keyAlias = DEFAULT_PRIVATE_KEY_ALIAS; +// guessing = true; +// } +// try { +// builder.privateKey(PkiUtil.loadPrivateKey(keyStore, keyAlias, keyPassphrase)); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to read private key from default alias", e); +// } else { +// throw e; +// } +// } +// +// List certChain = null; +// if (null == certChainAlias) { +// guessing = true; +// // by default, cert chain uses the same alias as private key +// certChainAlias = keyAlias; +// } else { +// guessing = false; +// } +// +// if (null != certChainAlias) { +// try { +// certChain = PkiUtil.loadCertChain(keyStore, certChainAlias); +// certChain.forEach(builder::addCertChain); +// } catch (Exception e) { +// if (guessing) { +// LOGGER.log(Level.FINEST, "Failed to certificate chain from alias \"" + certChainAlias + "\"", e); +// } else { +// throw e; +// } +// } +// } +// +// if (null == certAlias) { +// // no explicit public key certificate, just load it from cert chain if present +// if (null != certChain && !certChain.isEmpty()) { +// builder.publicKeyCert(certChain.get(0)); +// } +// } else { +// builder.publicKeyCert(PkiUtil.loadCertificate(keyStore, certAlias)); +// } +// +// if (addAllCertificates) { +// PkiUtil.loadCertificates(keyStore).forEach(builder::addCert); +// } else { +// certificateAliases.forEach(it -> builder.addCert(PkiUtil.loadCertificate(keyStore, it))); +// } +// } +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } +// } +// + +// /** +// * Builder for PEM files - accepts private key and certificate chain. Obtain an instance through {@link +// * FakeKeyConfigBean#pemBuilder()}. +// * +// * If you have "standard" linux/unix private key, you must run " +// * {@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa.p8}" on it to work with this builder for password protected +// * file; or "{@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa_nocrypt.p8 -nocrypt}" for unprotected file. +// * +// * The only supported format is PKCS#8. If you have a different format, you must to transform it to PKCS8 PEM format (to +// * use this builder), or to PKCS#12 keystore format (and use {@link KeystoreBuilder}). +// */ +// @Configured(ignoreBuildMethod = true) +// public static final class PemBuilder implements io.helidon.common.Builder { +// private final StreamHolder privateKeyStream = new StreamHolder("privateKey"); +// private final StreamHolder publicKeyStream = new StreamHolder("publicKey"); +// private final StreamHolder certChainStream = new StreamHolder("certChain"); +// private final StreamHolder certificateStream = new StreamHolder("certificate"); +// private char[] pemKeyPassphrase; +// +// private PemBuilder() { +// } +// +// /** +// * Read a private key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.resource") +// public PemBuilder key(Resource resource) { +// privateKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Read a public key from PEM format from a resource definition. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder publicKey(Resource resource) { +// publicKeyStream.stream(resource); +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// public PemBuilder keyPassphrase(char[] passphrase) { +// this.pemKeyPassphrase = Arrays.copyOf(passphrase, passphrase.length); +// +// return this; +// } +// +// /** +// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to +// * decrypt it. +// * +// * @param passphrase passphrase used to encrypt the private key +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "key.passphrase") +// public PemBuilder keyPassphrase(String passphrase) { +// return keyPassphrase(passphrase.toCharArray()); +// } +// +// /** +// * Load certificate chain from PEM resource. +// * +// * @param resource resource (e.g. classpath, file path, URL etc.) +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "cert-chain.resource") +// public PemBuilder certChain(Resource resource) { +// certChainStream.stream(resource); +// return this; +// } +// +// /** +// * Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. +// * +// * @param resource key resource (file, classpath, URL etc.) +// * @return updated builder instance +// */ +// public PemBuilder certificates(Resource resource) { +// certificateStream.stream(resource); +// return this; +// } +// +// /** +// * Build {@link FakeKeyConfigBean} based on information from PEM files only. +// * +// * @return new instance configured from this builder +// */ +// @Override +// public FakeKeyConfigBean build() { +// return toFullBuilder().build(); +// } +// +// /** +// * Get a builder filled from this builder to add additional information (such as public key from certificate etc.). +// * +// * @return builder for {@link FakeKeyConfigBean} +// */ +// public Builder toFullBuilder() { +// return updateBuilder(FakeKeyConfigBean.fullBuilder()); +// } +// +// private Builder updateBuilder(Builder builder) { +// if (privateKeyStream.isSet()) { +// builder.privateKey(PemReader.readPrivateKey(privateKeyStream.stream(), pemKeyPassphrase)); +// } +// if (publicKeyStream.isSet()) { +// builder.publicKey(PemReader.readPublicKey(publicKeyStream.stream())); +// } +// +// if (certChainStream.isSet()) { +// List chain = PemReader.readCertificates(certChainStream.stream()); +// chain.forEach(builder::addCertChain); +// if (!chain.isEmpty()) { +// builder.publicKeyCert(chain.get(0)); +// } +// } +// +// if (certificateStream.isSet()) { +// PemReader.readCertificates(certificateStream.stream()).forEach(builder::addCert); +// } +// +// return builder; +// } +// +// /** +// * Update this builder from configuration. +// * Expected keys: +// *
    +// *
  • pem-key-path - path to PEM private key file (PKCS#8 format)
  • +// *
  • pem-key-resource-path - path to resource on classpath
  • +// *
  • pem-key-passphrase - passphrase of private key if encrypted
  • +// *
  • pem-cert-chain-path - path to certificate chain PEM file
  • +// *
  • pem-cert-chain-resource-path - path to resource on classpath
  • +// *
+// * +// * @param config configuration to update builder from +// * @return updated builder instance +// */ +// public PemBuilder config(Config config) { +// Config pemConfig = config.get("pem"); +// pemConfig.get("key.resource").as(Resource::create).ifPresent(this::key); +// pemConfig.get("key.passphrase").asString().map(String::toCharArray).ifPresent(this::keyPassphrase); +// pemConfig.get("cert-chain.resource").as(Resource::create).ifPresent(this::certChain); +// pemConfig.get("certificates.resource").as(Resource::create).ifPresent(this::certificates); +// return this; +// } +// } +// +// private static final class StreamHolder { +// private final String baseMessage; +// private InputStream inputStream; +// private String message; +// +// private StreamHolder(String message) { +// this.baseMessage = message; +// this.message = message; +// } +// +// private boolean isSet() { +// return inputStream != null; +// } +// +// private void stream(Resource resource) { +// closeStream(); +// Objects.requireNonNull(resource, "Resource for \"" + message + "\" must not be null"); +// +// this.inputStream = resource.stream(); +// this.message = message + ":" + resource.sourceType() + ":" + resource.location(); +// } +// +// private InputStream stream() { +// return inputStream; +// } +// +// private String message() { +// return message; +// } +// +// private void closeStream() { +// if (null != inputStream) { +// try { +// inputStream.close(); +// } catch (IOException e) { +// LOGGER.log(Level.WARNING, "Failed to close input stream: " + message, e); +// } +// } +// message = baseMessage; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java new file mode 100644 index 00000000000..563db6276a3 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java @@ -0,0 +1,132 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka KeyConfig.Keystore.Builder + */ +@ConfigBean +public interface FakeKeystoreConfig { + + String DEFAULT_KEYSTORE_TYPE = "PKCS12"; + +// private final StreamHolder keystoreStream = new StreamHolder("keystore"); + +// default FakeKeystoreConfigBean trustStore() { +// return trustStore(true); +// } + + @ConfiguredOption(key = "trust-store") + boolean trustStore(); + +// /** +// * Keystore resource definition. +// * +// * @param keystore keystore resource, from file path, classpath, URL etc. +// * @return updated builder instance +// */ +// @ConfiguredOption(key = "resource", required = true) +// public KeystoreBuilder keystore(Resource keystore) { +// this.keystoreStream.stream(keystore); +// return this; +// } +// default DefaultFakeKeystoreConfigBean.Builder keystore(Resource keystore) { +// +// } + + @ConfiguredOption(key = "type", value = DEFAULT_KEYSTORE_TYPE) + String keystoreType(); + + @ConfiguredOption(key = "passphrase") + char[] keystorePassphrase(); + + @ConfiguredOption(key = "key.alias", value = "1") + String keyAlias(); + + @ConfiguredOption(key = "key.passphrase") + char[] keyPassphrase(); + + @ConfiguredOption(key = "cert.alias") + @Singular("certAlias") + List certAliases(); + + @ConfiguredOption(key = "cert-chain.alias") + String certChainAlias(); + + +// /** +// * Update this builder from configuration. +// * The following keys are expected under key {@code keystore}: +// *
    +// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • +// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • +// *
  • {@code passphrase}: passphrase of keystore, if required
  • +// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • +// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • +// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • +// *
  • {@code cert-chain.alias}: alias of certificate chain
  • +// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • +// *
+// * +// * @param config configuration instance +// * @return updated builder instance +// */ +// public KeystoreBuilder config(Config config) { +// Config keystoreConfig = config.get("keystore"); +// +// // the actual resource (file, classpath) with the bytes of the keystore +// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); +// +// // type of keystore +// keystoreConfig.get("type") +// .asString() +// .ifPresent(this::keystoreType); +// // password of the keystore +// keystoreConfig.get("passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keystorePassphrase); +// // private key alias +// keystoreConfig.get("key.alias") +// .asString() +// .ifPresent(this::keyAlias); +// // private key password +// keystoreConfig.get("key.passphrase") +// .asString() +// .map(String::toCharArray) +// .ifPresent(this::keyPassphrase); +// keystoreConfig.get("cert.alias") +// .asString() +// .ifPresent(this::certAlias); +// keystoreConfig.get("cert-chain.alias") +// .asString() +// .ifPresent(this::certChainAlias); +// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) +// keystoreConfig.get("trust-store") +// .asBoolean() +// .ifPresent(this::trustStore); +// +// return this; +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java new file mode 100644 index 00000000000..238f795421a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.pico.builder.config.fakes.config; + +public enum FakeNettyClientAuth { + NONE, + OPTIONAL, + REQUIRE; + + private FakeNettyClientAuth() { + } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java new file mode 100644 index 00000000000..6a8f321ae6d --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java @@ -0,0 +1,179 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka PathTracing. + * + * Traced system configuration for web server for a specific path. + */ +@ConfigBean +public interface FakePathTracingConfig { +// /** +// * Create a new traced path configuration from {@link io.helidon.config.Config}. +// * @param config config of a path +// * @return traced path configuration +// */ +// static FakePathTracingConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * Create a new builder to configure traced path configuration. +// * +// * @return a new builder instance +// */ +// static Builder builder() { +// return new Builder(); +// } + + /** + * Path this configuration should configure. + * + * @return path on the web server + */ + String path(); + + /** + * Method(s) this configuration should be valid for. This can be used to restrict the configuration + * only to specific HTTP methods (such as {@code GET} or {@code POST}). + * + * @return list of methods, if empty, this configuration is valid for any method + */ + @Singular("method") // Builder::addMethod(String method); + List methods(); + +// /** +// * Associated configuration of tracing valid for the configured path and (possibly) methods. +// * +// * @return traced system configuration +// */ + @ConfiguredOption(required = true) + FakeTracingConfig tracedConfig(); + +// Optional tracedConfig(); + + +// /** +// * Fluent API builder for {@link FakePathTracingConfigBean}. +// */ +// final class Builder implements io.helidon.common.Builder { +// private final List methods = new LinkedList<>(); +// private String path; +// private TracingConfig tracedConfig; +// +// private Builder() { +// } +// +// @Override +// public FakePathTracingConfigBean build() { +// // immutable +// final String finalPath = path; +// final List finalMethods = new LinkedList<>(methods); +// final TracingConfig finalTracingConfig = tracedConfig; +// +// return new FakePathTracingConfigBean() { +// @Override +// public String path() { +// return finalPath; +// } +// +// @Override +// public List methods() { +// return finalMethods; +// } +// +// @Override +// public TracingConfig tracedConfig() { +// return finalTracingConfig; +// } +// +// @Override +// public String toString() { +// return path + "(" + finalMethods + "): " + finalTracingConfig; +// } +// }; +// } +// +// /** +// * Update this builder from provided {@link io.helidon.config.Config}. +// * +// * @param config config to update this builder from +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// path(config.get("path").asString().get()); +// List methods = config.get("methods").asList(String.class).orElse(null); +// if (null != methods) { +// methods(methods); +// } +// tracingConfig(TracingConfig.create(config)); +// +// return this; +// } +// +// /** +// * Path to register the traced configuration on. +// * +// * @param path path as understood by {@link io.helidon.webserver.Routing.Builder} of web server +// * @return updated builder instance +// */ +// public Builder path(String path) { +// this.path = path; +// return this; +// } +// +// /** +// * HTTP methods to restrict registration of this configuration on web server. +// * @param methods list of methods to use, empty means all methods +// * @return updated builder instance +// */ +// public Builder methods(List methods) { +// this.methods.clear(); +// this.methods.addAll(methods); +// return this; +// } +// +// /** +// * Add a new HTTP method to restrict this configuration for. +// * +// * @param method method to add to the list of supported methods +// * @return updated builder instance +// */ +// public Builder addMethod(String method) { +// this.methods.add(method); +// return this; +// } +// +// /** +// * Configuration of a traced system to use on this path and possibly method(s). +// * +// * @param tracedConfig configuration of components, spans and span logs +// * @return updated builder instance +// */ +// public Builder tracingConfig(TracingConfig tracedConfig) { +// this.tracedConfig = tracedConfig; +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java new file mode 100644 index 00000000000..502b41fdec1 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java @@ -0,0 +1,699 @@ +/* + * 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.pico.builder.config.fakes.config; + +/* + * 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. + */ + +/** + * aka Routing. + * + * an annotation to get something discovered (i.e., @CustomConfigBean?) + * + * Routing represents composition of HTTP request-response handlers with routing rules. + * It is a cornerstone of the {@link io.helidon.pico.config.fake.helidon.WebServer}. + */ +public interface FakeRoutingConfig extends FakeServerLifecycle { + +// void route(BareRequest bareRequest, BareResponse bareResponse); +// +// /** +// * Creates new instance of {@link Builder routing builder}. +// * +// * @return a new instance +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * An API to define HTTP request routing rules. +// * +// * @see Builder +// */ +// interface Rules { +// /** +// * Configuration of tracing for this routing. +// * The configuration may control whether to log specific components, +// * spans and span logs, either globally, or for a specific path and method combinations. +// * +// * @param webTracingConfig WebServer tracing configuration +// * @return Updated routing configuration +// */ +// Rules register(WebTracingConfig webTracingConfig); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return Updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(Supplier... serviceBuilders); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param services services to register +// * @return Updated routing configuration +// */ +// Rules register(String pathPattern, Service... services); +// +// /** +// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param serviceBuilders service builder to register; they will be built as a first step of this +// * method execution +// * @return an updated routing configuration +// */ +// @SuppressWarnings("unchecked") +// Rules register(String pathPattern, Supplier... serviceBuilders); +// +// /** +// * Routes all GET requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(Handler... requestHandlers); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(String pathPattern, Handler... requestHandlers); +// +// /** +// * Add a route. This allows also protocol version specific routing. +// * +// * @param route route to add +// * @return updated rules +// */ +// Rules route(HttpRoute route); +// +// /** +// * Routes GET requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules get(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all PUT requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for a registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules put(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all POST requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes POST requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules post(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all RFC 5789 PATCH requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules patch(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all DELETE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules delete(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all OPTIONS requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules options(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all HEAD requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules head(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all TRACE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules trace(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes all requests to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes all requests with corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules any(PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Routes requests any specified method to provided handler(s). Request handler can call {@link ServerRequest#next()} +// * to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, String pathPattern, Handler... requestHandlers); +// +// /** +// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call +// * {@link ServerRequest#next()} to continue processing on the next registered handler. +// * +// * @param methods HTTP methods +// * @param pathMatcher define path for registered router +// * @param requestHandlers handlers to process HTTP request +// * @return an updated routing configuration +// */ +// Rules anyOf(Iterable methods, PathMatcher pathMatcher, Handler... requestHandlers); +// +// /** +// * Registers callback on created new {@link WebServer} instance with this routing. +// * +// * @param webServerConsumer a WebServer creation callback +// * @return updated routing configuration +// */ +// Rules onNewWebServer(Consumer webServerConsumer); +// } +// +// /** +// * A {@link Routing} builder. +// */ +// class Builder implements Rules, io.helidon.common.Builder { +// +// private final RouteListRoutingRules delegate = new RouteListRoutingRules(); +// private final List> errorHandlerRecords = new ArrayList<>(); +// private boolean tracingRegistered; +// +// /** +// * Creates new instance. +// */ +// private Builder() { +// } +// +// // --------------- ROUTING API +// +// @Override +// public Builder register(WebTracingConfig webTracingConfig) { +// this.tracingRegistered = true; +// delegate.register(webTracingConfig); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(Supplier... serviceBuilders) { +// delegate.register(serviceBuilders); +// return this; +// } +// +// @Override +// public Builder register(Service... services) { +// delegate.register(services); +// return this; +// } +// +// @Override +// public Builder register(String pathPattern, Service... services) { +// delegate.register(pathPattern, services); +// return this; +// } +// +// @Override +// @SuppressWarnings("unchecked") +// public Builder register(String pathPattern, Supplier... serviceBuilders) { +// delegate.register(pathPattern, serviceBuilders); +// return this; +// } +// +// @Override +// public Builder get(Handler... requestHandlers) { +// delegate.get(requestHandlers); +// return this; +// } +// +// @Override +// public Builder get(String pathPattern, Handler... requestHandlers) { +// delegate.get(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder route(HttpRoute route) { +// delegate.register(route); +// return this; +// } +// +// @Override +// public Builder get(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.get(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(Handler... requestHandlers) { +// delegate.put(requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(String pathPattern, Handler... requestHandlers) { +// delegate.put(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder put(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.put(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(Handler... requestHandlers) { +// delegate.post(requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(String pathPattern, Handler... requestHandlers) { +// delegate.post(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder post(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.post(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(Handler... requestHandlers) { +// delegate.patch(requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(String pathPattern, Handler... requestHandlers) { +// delegate.patch(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder patch(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.patch(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(Handler... requestHandlers) { +// delegate.delete(requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(String pathPattern, Handler... requestHandlers) { +// delegate.delete(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder delete(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.delete(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(Handler... requestHandlers) { +// delegate.options(requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(String pathPattern, Handler... requestHandlers) { +// delegate.options(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder options(PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.options(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(Handler... requestHandlers) { +// delegate.head(requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(String pathPattern, Handler... requestHandlers) { +// delegate.head(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder head(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.head(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(Handler... requestHandlers) { +// delegate.trace(requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(String pathPattern, Handler... requestHandlers) { +// delegate.trace(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder trace(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.trace(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(Handler... requestHandlers) { +// delegate.any(requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(String pathPattern, Handler... requestHandlers) { +// delegate.any(pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder any(PathMatcher pathMatcher, Handler... requestHandlers) { +// delegate.any(pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, Handler... requestHandlers) { +// delegate.anyOf(methods, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, String pathPattern, Handler... requestHandlers) { +// delegate.anyOf(methods, pathPattern, requestHandlers); +// return this; +// } +// +// @Override +// public Builder anyOf(Iterable methods, +// PathMatcher pathMatcher, +// Handler... requestHandlers) { +// delegate.anyOf(methods, pathMatcher, requestHandlers); +// return this; +// } +// +// @Override +// public Builder onNewWebServer(Consumer webServerConsumer) { +// delegate.onNewWebServer(webServerConsumer); +// return this; +// } +// // --------------- ERROR API +// +// /** +// * Registers an error handler that handles the given type of exceptions. +// * +// * @param exceptionClass the type of exception to handle by this handler +// * @param errorHandler the error handler +// * @param an error handler type +// * @return an updated builder +// */ +// public Builder error(Class exceptionClass, ErrorHandler errorHandler) { +// if (errorHandler == null) { +// return this; +// } +// errorHandlerRecords.add(RequestRouting.ErrorHandlerRecord.of(exceptionClass, errorHandler)); +// +// return this; +// } +// +// // --------------- BUILD API +// +// /** +// * Builds a new routing instance. +// * +// * @return a new instance +// */ +// public Routing build() { +// if (!tracingRegistered) { +// register(WebTracingConfig.create()); +// } +// RouteListRoutingRules.Aggregation aggregate = delegate.aggregate(); +// return new RequestRouting(aggregate.routeList(), errorHandlerRecords, aggregate.newWebServerCallbacks()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java new file mode 100644 index 00000000000..e5b1f3f4a61 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java @@ -0,0 +1,763 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka ServerConfiguration. + */ +@ConfigBean +public interface FakeServerConfig extends FakeSocketConfig { + + /** + * Returns the count of threads in the pool used to process HTTP requests. + *

+ * Default value is {@link Runtime#availableProcessors()}. + * + * @return a workers count + */ + int workersCount(); + + /** + * Returns a server port to listen on with the default server socket. If port is + * {@code 0} then any available ephemeral port will be used. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return the server port of the default server socket + */ + @Override + int port(); + +// /** +// * Returns local address where the server listens on with the default server socket. +// * If {@code null} then listens an all local addresses. +// *

+// * Additional named server socket configuration is accessible through +// * the {@link #socket(String)} and {@link #sockets()} methods. +// * +// * @return an address to bind with the default server socket; {@code null} for all local addresses +// */ +// @Override +// InetAddress bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the default server + * socket. + *

+ * Default value is {@link FakeSocketConfig#DEFAULT_BACKLOG_SIZE}. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a maximum length of the queue of incoming connections + */ + @Override + int backlog(); + + /** + * Returns a default server socket timeout in milliseconds or {@code 0} for an infinite timeout. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a default server socket timeout in milliseconds or {@code 0} + */ + @Override + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * default server socket. + *

+ * If {@code 0} then use implementation default. + *

+ * Additional named server socket configuration is accessible through + * the {@link #socket(String)} and {@link #sockets()} methods. + * + * @return a buffer size in bytes of the default server socket or {@code 0} + */ + @Override + int receiveBufferSize(); + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code null} if there is no such + * named server socket + * @deprecated since 2.0.0, please use {@link #namedSocket(String)} instead + */ + @Deprecated + default FakeSocketConfig socket(String name) { + return namedSocket(name).orElse(null); + } + + /** + * A socket configuration of an additional named server socket. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @param name the name of the additional server socket + * @return an additional named server socket configuration or {@code empty} if there is no such + * named server socket configured + */ + default Optional namedSocket(String name) { + return Optional.ofNullable(sockets().get(name)); + } + + /** + * A map of all the configured server sockets; that is the default server socket + * which is identified by the key {@link io.helidon.pico.config.fake.helidon.WebServer#DEFAULT_SOCKET_NAME} and also all the additional + * named server socket configurations. + *

+ * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured + * + * @return a map of all the configured server sockets, never null + */ + @Singular("socket") + Map sockets(); + + /** + * The maximum amount of time that the server will wait to shut + * down regardless of the value of any additionally requested + * quiet period. + * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(10L)}.

+ * + * @return the {@link java.time.Duration} to use + */ +// TODO: @DefaultValue (Duration translation) + @ConfiguredOption(key = "whatever") + default Duration maxShutdownTimeout() { + return Duration.ofSeconds(10L); + } + + /** + * The quiet period during which the webserver will wait for new + * incoming connections after it has been told to shut down. + * + *

The webserver will wait no longer than the duration returned + * by the {@link #maxShutdownTimeout()} method.

+ * + *

The default implementation of this method returns {@link + * java.time.Duration#ofSeconds(long) Duration.ofSeconds(0L)}, indicating + * that there will be no quiet period.

+ * + * @return the {@link java.time.Duration} to use + */ + default Duration shutdownQuietPeriod() { + return Duration.ofSeconds(0L); + } + +// /** +// * Returns a Tracer. +// * +// * @return a tracer to use - never {@code null} +// */ +// Tracer tracer(); + +// /** +// * The top level {@link io.helidon.common.context.Context} to be used by this webserver. +// * @return a context instance with registered application scoped instances +// */ +// Context context(); +// +// /** +// * Returns an optional {@link Transport}. +// * +// * @return an optional {@link Transport} +// */ +// default Optional transport() { +// return Optional.ofNullable(null); +// } + + /** + * Whether to print details of HelidonFeatures. + * + * @return whether to print details + */ + boolean printFeatureDetails(); + +// /** +// * Creates new instance with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new instance +// */ +// static FakeServerConfigBean create(Config config) { +// return builder(config).build(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder}. +// * +// * @return a new builder instance +// * +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()} instead +// */ +// @Deprecated +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Creates new instance of a {@link Builder server configuration builder} with defaults from external configuration source. +// * +// * @param config the externalized configuration +// * @return a new builder instance +// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()}, then +// * {@link WebServer.Builder#config(io.helidon.config.Config)}, or +// * {@link io.helidon.webserver.WebServer#create(Routing, io.helidon.config.Config)} +// */ +// @Deprecated +// static Builder builder(Config config) { +// return new Builder().config(config); +// } +// +// /** +// * A {@link FakeServerConfigBean} builder. +// * +// * @deprecated since 2.0.0 - use {@link io.helidon.webserver.WebServer.Builder} instead +// */ +// @Deprecated +// final class Builder implements FakeSocketConfigBean.SocketConfigurationBuilder, +// io.helidon.common.Builder { +// +// private static final AtomicInteger WEBSERVER_COUNTER = new AtomicInteger(1); +// private final Map socketBuilders = new HashMap<>(); +// private final Map socketsConfigs = new HashMap<>(); +// private int workers; +// private Tracer tracer; +// private Duration maxShutdownTimeout; +// private Duration shutdownQuietPeriod; +// private Optional transport; +// private Context context; +// private boolean printFeatureDetails; +// +// private Builder() { +// transport = Optional.ofNullable(null); +// maxShutdownTimeout = Duration.ofSeconds(10L); +// shutdownQuietPeriod = Duration.ofSeconds(0L); +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContext ssl context +// * @return an updated builder +// */ +// public Builder ssl(SSLContext sslContext) { +// defaultSocketBuilder().ssl(sslContext); +// return this; +// } +// +// /** +// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. +// * +// * @param sslContextBuilder ssl context builder; will be built as a first step of this method execution +// * @return an updated builder +// */ +// public Builder ssl(Supplier sslContextBuilder) { +// defaultSocketBuilder().ssl(sslContextBuilder); +// return this; +// } +// +// /** +// * Sets server port. If port is {@code 0} or less then any available ephemeral port will be used. +// *

+// * Configuration key: {@code port} +// * +// * @param port the server port +// * @return an updated builder +// */ +// public Builder port(int port) { +// defaultSocketBuilder().port(port); +// return this; +// } +// +// /** +// * Sets a local address for server to bind. If {@code null} then listens an all local addresses. +// *

+// * Configuration key: {@code bind-address} +// * +// * @param bindAddress the address to bind the server or {@code null} for all local addresses +// * @return an updated builder +// */ +// public Builder bindAddress(InetAddress bindAddress) { +// defaultSocketBuilder().bindAddress(bindAddress); +// return this; +// } +// +// /** +// * Sets a maximum length of the queue of incoming connections. Default value is {@code 1024}. +// *

+// * Configuration key: {@code backlog} +// * +// * @param size the maximum length of the queue of incoming connections +// * @return an updated builder +// */ +// public Builder backlog(int size) { +// defaultSocketBuilder().backlog(size); +// return this; +// } +// +// /** +// * Sets a socket timeout in milliseconds or {@code 0} for infinite timeout. +// *

+// * Configuration key: {@code timeout} +// * +// * @param milliseconds a socket timeout in milliseconds or {@code 0} +// * @return an updated builder +// */ +// public Builder timeout(int milliseconds) { +// defaultSocketBuilder().timeoutMillis(milliseconds); +// return this; +// } +// +// /** +// * Propose value of the TCP receive window that is advertised to the remote peer. +// * If {@code 0} then implementation default is used. +// *

+// * Configuration key: {@code receive-buffer} +// * +// * @param bytes a buffer size in bytes or {@code 0} +// * @return an updated builder +// */ +// public Builder receiveBufferSize(int bytes) { +// defaultSocketBuilder().receiveBufferSize(bytes); +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// defaultSocketBuilder().maxHeaderSize(size); +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// defaultSocketBuilder().maxInitialLineLength(length); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param port the port to bind; if {@code 0} or less, any available ephemeral port will be used +// * @param bindAddress the address to bind; if {@code null}, all local addresses will be bound +// * @return an updated builder +// * +// * @deprecated since 2.0.0, please use {@link #addSocket(String, FakeSocketConfigBean)} instead +// */ +// @Deprecated +// public Builder addSocket(String name, int port, InetAddress bindAddress) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// return addSocket(name, FakeSocketConfigBean.builder() +// .port(port) +// .bindAddress(bindAddress)); +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketsConfigs.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfiguration the additional named server socket configuration builder +// * @return an updated builder +// */ +// public Builder addSocket(String name, FakeSocketConfigBean.Builder socketConfiguration) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// this.socketBuilders.put(name, socketConfiguration); +// return this; +// } +// +// /** +// * Adds an additional named server socket configuration builder. As a result, the server will listen +// * on multiple ports. +// *

+// * An additional named server socket may have a dedicated {@link Routing} configured +// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. +// * +// * @param name the name of the additional server socket configuration +// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as +// * a first step of this method execution +// * @return an updated builder +// */ +// public Builder addSocket(String name, Supplier socketConfigurationBuilder) { +// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); +// +// return addSocket(name, socketConfigurationBuilder != null ? socketConfigurationBuilder.get() : null); +// } +// +// /** +// * Sets a count of threads in pool used to process HTTP requests. +// * Default value is {@code CPU_COUNT * 2}. +// *

+// * Configuration key: {@code workers} +// * +// * @param workers a workers count +// * @return an updated builder +// */ +// public Builder workersCount(int workers) { +// this.workers = workers; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracer a tracer to set +// * @return an updated builder +// */ +// public Builder tracer(Tracer tracer) { +// this.tracer = tracer; +// return this; +// } +// +// /** +// * Sets a tracer. +// * +// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution +// * @return updated builder +// */ +// public Builder tracer(Supplier tracerBuilder) { +// return tracer(tracerBuilder.get()); +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(String... protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the default server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return an updated builder +// */ +// public Builder enabledSSlProtocols(List protocols) { +// defaultSocketBuilder().enabledSSlProtocols(protocols); +// return this; +// } +// +// /** +// * Configure maximum client payload size. +// * @param size maximum payload size +// * @return an updated builder +// */ +// @Override +// public Builder maxPayloadSize(long size) { +// defaultSocketBuilder().maxPayloadSize(size); +// return this; +// } +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @Override +// public Builder maxUpgradeContentLength(int size) { +// defaultSocketBuilder().maxUpgradeContentLength(size); +// return this; +// } +// +// /** +// * Configure the maximum amount of time that the server will wait to shut +// * down regardless of the value of any additionally requested +// * quiet period. +// * @param maxShutdownTimeout the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder maxShutdownTimeout(Duration maxShutdownTimeout) { +// this.maxShutdownTimeout = +// Objects.requireNonNull(maxShutdownTimeout, "Parameter 'maxShutdownTimeout' must not be null!"); +// return this; +// } +// +// /** +// * Configure the quiet period during which the webserver will wait for new +// * incoming connections after it has been told to shut down. +// * @param shutdownQuietPeriod the {@link Duration} to use +// * @return an updated builder +// */ +// public Builder shutdownQuietPeriod(Duration shutdownQuietPeriod) { +// this.shutdownQuietPeriod = +// Objects.requireNonNull(shutdownQuietPeriod, "Parameter 'shutdownQuietPeriod' must not be null!"); +// return this; +// } +// +// /** +// * Configure transport. +// * @param transport a {@link Transport} +// * @return an updated builder +// */ +// public Builder transport(Transport transport) { +// this.transport = Optional.of(transport); +// return this; +// } +// +// /** +// * Set to {@code true} to print detailed feature information on startup. +// * +// * @param print whether to print details or not +// * @return updated builder instance +// * @see io.helidon.common.HelidonFeatures +// */ +// public Builder printFeatureDetails(boolean print) { +// this.printFeatureDetails = print; +// return this; +// } +// +// /** +// * Configure the application scoped context to be used as a parent for webserver request contexts. +// * @param context top level context +// * @return an updated builder +// */ +// public Builder context(Context context) { +// this.context = context; +// +// return this; +// } +// +// private InetAddress string2InetAddress(String address) { +// try { +// return InetAddress.getByName(address); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * Sets configuration values included in provided {@link Config} parameter. +// *

+// * It can be used for configuration externalisation. +// *

+// * All parameters sets before this method call can be seen as defaults and all parameters sets after can be seen +// * as forced. +// * +// * @param config the configuration to use +// * @return an updated builder +// */ +// public Builder config(Config config) { +// if (config == null) { +// return this; +// } +// +// defaultSocketBuilder().config(config); +// +// config.get("host").asString().ifPresent(defaultSocketBuilder()::host); +// +// DeprecatedConfig.get(config, "worker-count", "workers") +// .asInt() +// .ifPresent(this::workersCount); +// +// config.get("features.print-details").asBoolean().ifPresent(this::printFeatureDetails); +// +// // shutdown timeouts +// config.get("max-shutdown-timeout-seconds").asLong().ifPresent(it -> maxShutdownTimeout(Duration.ofSeconds(it))); +// config.get("shutdown-quiet-period-seconds").asLong().ifPresent(it -> shutdownQuietPeriod(Duration.ofSeconds(it))); +// +// // sockets +// Config socketsConfig = config.get("sockets"); +// if (socketsConfig.exists()) { +// List socketConfigs = socketsConfig.asNodeList().orElse(List.of()); +// for (Config socketConfig : socketConfigs) { +// // the whole section checking the socket name can be removed +// // when we remove deprecated methods with socket name on server builder +// String socketName; +// +// String nodeName = socketConfig.name(); +// Optional maybeSocketName = socketConfig.get("name").asString().asOptional(); +// +// socketName = maybeSocketName.orElse(nodeName); +// +// // log warning for deprecated config +// try { +// Integer.parseInt(nodeName); +// if (socketName.equals(nodeName) && maybeSocketName.isEmpty()) { +// throw new ConfigException("Cannot find \"name\" key for socket configuration " + socketConfig.key()); +// } +// } catch (NumberFormatException e) { +// // this is old approach +// Logger.getLogger(SocketConfigurationBuilder.class.getName()) +// .warning("Socket configuration at " + socketConfig.key() + " is deprecated. Please use an array " +// + "with \"name\" key to define the socket name."); +// } +// +// FakeSocketConfigBean.Builder socket = FakeSocketConfigBean.builder() +// .name(socketName) +// .config(socketConfig); +// +// socketBuilders.put(socket.name(), socket); +// } +// } +// +// return this; +// } +// +// /** +// * Builds a new configuration instance. +// * +// * @return a new instance +// */ +// @Override +// public FakeServerConfigBean build() { +// if (null == context) { +// // I do not expect "unlimited" number of webservers +// // in case somebody spins a huge number up, the counter will cycle to negative numbers once +// // Integer.MAX_VALUE is reached. +// context = Context.builder() +// .id("web-" + WEBSERVER_COUNTER.getAndIncrement()) +// .build(); +// } +// +// Optional maybeTracer = context.get(Tracer.class); +// +// if (null == this.tracer) { +// this.tracer = maybeTracer.orElseGet(Tracer::global); +// } +// +// if (maybeTracer.isEmpty()) { +// context.register(this.tracer); +// } +// +// if (workers <= 0) { +// workers = Runtime.getRuntime().availableProcessors(); +// } +// +// return new ServerBasicConfig(this); +// } +// +// FakeSocketConfigBean.Builder defaultSocketBuilder() { +// return socketBuilder(WebServer.DEFAULT_SOCKET_NAME); +// } +// +// FakeSocketConfigBean.Builder socketBuilder(String socketName) { +// return socketBuilders.computeIfAbsent(socketName, k -> FakeSocketConfigBean.builder().name(socketName)); +// } +// +// Map sockets() { +// Set builtSocketConfigsKeys = socketsConfigs.keySet(); +// Map result = +// new HashMap<>(this.socketBuilders.size() + this.socketsConfigs.size()); +// for (Map.Entry e : this.socketBuilders.entrySet()) { +// String key = e.getKey(); +// if (builtSocketConfigsKeys.contains(key)) { +// throw new IllegalStateException("Both mutable and immutable socket configuration provided for named socket " +// + key); +// } +// result.put(key, e.getValue().build()); +// } +// +// result.putAll(this.socketsConfigs); +// return result; +// } +// +// int workers() { +// return workers; +// } +// +// Tracer tracer() { +// return tracer; +// } +// +// Duration maxShutdownTimeout() { +// return maxShutdownTimeout; +// } +// +// Duration shutdownQuietPeriod() { +// return shutdownQuietPeriod; +// } +// +// Optional transport() { +// return transport; +// } +// +// Context context() { +// return context; +// } +// +// boolean printFeatureDetails() { +// return printFeatureDetails; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// defaultSocketBuilder().timeout(amount, unit); +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// defaultSocketBuilder().tls(webServerTls); +// return this; +// } +// +// @Override +// public Builder enableCompression(boolean value) { +// defaultSocketBuilder().enableCompression(value); +// return this; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java new file mode 100644 index 00000000000..49dd3296f63 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java @@ -0,0 +1,38 @@ +/* + * 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.pico.builder.config.fakes.config; + +/** + * aka ServerLifecycle. + * + * Basic server lifecycle operations. + */ +public interface FakeServerLifecycle { + +// /** +// * Before server start. +// */ +// default void beforeStart() { +// } +// +// /** +// * After server stop. +// */ +// default void afterStop() { +// } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java new file mode 100644 index 00000000000..6adf615a31b --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java @@ -0,0 +1,849 @@ +/* + * 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.pico.builder.config.fakes.config; + +/* + * 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 java.util.Optional; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.fakes.WebServer; + +/** + * aka ServerConfiguration. + * + * The SocketConfiguration configures a port to listen on and its associated server socket parameters. + */ +@ConfigBean +public interface FakeSocketConfig { + + /** + * The default backlog size to configure the server sockets with if no other value + * is provided. + */ + int DEFAULT_BACKLOG_SIZE = 1024; + + /** + * Name of this socket. + * Default to WebServer#DEFAULT_SOCKET_NAME for the main and + * default server socket. All other sockets must be named. + * + * @return name of this socket + */ +// default String name() { +// return WebServer.DEFAULT_SOCKET_NAME; +// } + @ConfiguredOption(WebServer.DEFAULT_SOCKET_NAME) + String name(); + + /** + * Returns a server port to listen on with the server socket. If port is + * {@code 0} then any available ephemeral port will be used. + * + * @return the server port of the server socket + */ + int port(); + +// /** +// * Returns local address where the server listens on with the server socket. +// * If {@code null} then listens an all local addresses. +// * +// * @return an address to bind with the server socket; {@code null} for all local addresses +// */ +// InetAddress bindAddress(); + @ConfiguredOption(key = "bind-address") + String bindAddress(); + + /** + * Returns a maximum length of the queue of incoming connections on the server + * socket. + *

+ * Default value is {@link #DEFAULT_BACKLOG_SIZE}. + * + * @return a maximum length of the queue of incoming connections + */ + @ConfiguredOption("1024") + int backlog(); + + /** + * Returns a server socket timeout in milliseconds or {@code 0} for an infinite timeout. + * + * @return a server socket timeout in milliseconds or {@code 0} + */ + @ConfiguredOption(key = "timeout-millis") + int timeoutMillis(); + + /** + * Returns proposed value of the TCP receive window that is advertised to the remote peer on the + * server socket. + *

+ * If {@code 0} then use implementation default. + * + * @return a buffer size in bytes of the server socket or {@code 0} + */ + int receiveBufferSize(); + + /** + * Return a {@link FakeWebServerTlsConfig} containing server TLS configuration. When empty {@link java.util.Optional} is returned + * no TLS should be configured. + * + * @return web server tls configuration + */ + Optional tls(); + + /** + * Returns a {@link javax.net.ssl.SSLContext} to use with the server socket. If not {@code null} then + * the server enforces an SSL communication. + * + * @deprecated use {@code tls().sslContext()} instead. This method will be removed at 3.0.0 version. + * @return a SSL context to use + */ + @Deprecated(since = "2.3.1", forRemoval = true) + SSLContext ssl(); + + /** + * Returns the SSL protocols to enable, or {@code null} to enable the default + * protocols. + * @deprecated use {@code tls().enabledTlsProtocols()} instead. This method will be removed at 3.0.0 version. + * @return the SSL protocols to enable + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set enabledSslProtocols(); + + /** + * Return the allowed cipher suite of the TLS. If empty set is returned, the default cipher suite is used. + * + * @deprecated use {@code tls().cipherSuite()} instead. This method will be removed at 3.0.0 version. + * @return the allowed cipher suite + */ + @Deprecated(since = "2.3.1", forRemoval = true) + Set allowedCipherSuite(); + + /** + * Whether to require client authentication or not. + * + * @deprecated use {@code tls().clientAuth()} instead. This method will be removed at 3.0.0 version. + * @return client authentication + */ + @Deprecated(since = "2.3.1", forRemoval = true) + FakeNettyClientAuth clientAuth(); + + /** + * Whether this socket is enabled (and will be opened on server startup), or disabled + * (and ignored on server startup). + * + * @return {@code true} for enabled socket, {@code false} for socket that should not be opened + */ +// default boolean enabled() { +// return true; +// } + @ConfiguredOption("true") + boolean enabled(); + + /** + * Maximal size of all headers combined. + * + * @return size in bytes + */ + // TODO: should we automatically translate camel-case to dashes? + @ConfiguredOption(key = "max-header-size", value = "8192") + int maxHeaderSize(); + + /** + * Maximal length of the initial HTTP line. + * + * @return length + */ + @ConfiguredOption("4096") + int maxInitialLineLength(); + + /** + * Maximal size of a single chunk of received data. + * + * @return chunk size + */ + int maxChunkSize(); + + /** + * Whether to validate HTTP header names. + * When set to {@code true}, we make sure the header name is a valid string + * + * @return {@code true} if headers should be validated + */ + boolean validateHeaders(); + + /** + * Whether to allow negotiation for a gzip/deflate content encoding. Supporting + * HTTP compression may interfere with application that use streaming and other + * similar features. Thus, it defaults to {@code false}. + * + * @return compression flag + */ +// default boolean enableCompression() { +// return false; +// } + boolean enableCompression(); + + /** + * Maximum size allowed for an HTTP payload in a client request. A negative + * value indicates that there is no maximum set. + * + * @return maximum payload size + */ +// default long maxPayloadSize() { +// return -1L; +// } + @ConfiguredOption("-1") + long maxPayloadSize(); + + /** + * Initial size of the buffer used to parse HTTP line and headers. + * + * @return initial size of the buffer + */ + int initialBufferSize(); + + /** + * Maximum length of the content of an upgrade request. + * + * @return maximum length of the content of an upgrade request + */ +// default int maxUpgradeContentLength() { +// return 64 * 1024; +// } + @ConfiguredOption("65536") + int maxUpgradeContentLength(); + +// /** +// * Creates a builder of {@link FakeSocketConfigBean} class. +// * +// * @return a builder +// */ +// static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create a default named configuration. +// * +// * @param name name of the socket +// * @return a new socket configuration with defaults +// */ +// static FakeSocketConfigBean create(String name) { +// return builder() +// .name(name) +// .build(); +// } +// +// /** +// * Socket configuration builder API, used by {@link io.helidon.webserver.SocketConfiguration.Builder} +// * to configure additional sockets, and by {@link io.helidon.webserver.WebServer.Builder} to +// * configure the default socket. +// * +// * @param type of the subclass of this class to provide correct fluent API +// */ +// @Configured +// interface SocketConfigurationBuilder> { +// /** +// * Configures a server port to listen on with the server socket. If port is +// * {@code 0} then any available ephemeral port will be used. +// * +// * @param port the server port of the server socket +// * @return this builder +// */ +// @ConfiguredOption("0") +// B port(int port); +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param address an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// * @throws io.helidon.config.ConfigException in case the address provided is not a valid host address +// */ +// @ConfiguredOption(deprecated = true) +// default B bindAddress(String address) { +// try { +// return bindAddress(InetAddress.getByName(address)); +// } catch (UnknownHostException e) { +// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); +// } +// } +// +// /** +// * A helper method that just calls {@link #bindAddress(String)}. +// * +// * @param address host to listen on +// * @return this builder +// */ +// @ConfiguredOption +// default B host(String address) { +// return bindAddress(address); +// } +// +// /** +// * Configures local address where the server listens on with the server socket. +// * If not configured, then listens an all local addresses. +// * +// * @param bindAddress an address to bind with the server socket +// * @return this builder +// * @throws java.lang.NullPointerException in case the bind address is null +// */ +// B bindAddress(InetAddress bindAddress); +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// @ConfiguredOption("1024") +// B backlog(int backlog); +// +// /** +// * Configures a server socket timeout. +// * +// * @param amount an amount of time to configure the timeout, use {@code 0} for infinite timeout +// * @param unit time unit to use with the configured amount +// * @return this builder +// */ +// @ConfiguredOption(key = "timeout-millis", type = Long.class, value = "0", +// description = "Socket timeout in milliseconds") +// B timeout(long amount, TimeUnit unit); +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @ConfiguredOption +// B receiveBufferSize(int receiveBufferSize); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * If this method is called, any other method except for {@link #tls(java.util.function.Supplier)}¨ +// * and repeated invocation of this method would be ignored. +// *

+// * If this method is called again, the previous configuration would be ignored. +// * +// * @param webServerTls ssl configuration to use with this socket +// * @return this builder +// */ +// @ConfiguredOption +// B tls(FakeWebServerTlsConfigBean webServerTls); +// +// /** +// * Configures SSL for this socket. When configured, the server enforces SSL +// * configuration. +// * +// * @param tlsConfig supplier ssl configuration to use with this socket +// * @return this builder +// */ +// default B tls(Supplier tlsConfig) { +// return tls(tlsConfig.get()); +// } +// +// /** +// * Maximal number of bytes of all header values combined. When a bigger value is received, a +// * {@link io.helidon.common.http.Http.Status#BAD_REQUEST_400} +// * is returned. +// *

+// * Default is {@code 8192} +// * +// * @param size maximal number of bytes of combined header values +// * @return this builder +// */ +// @ConfiguredOption("8192") +// B maxHeaderSize(int size); +// +// /** +// * Maximal number of characters in the initial HTTP line. +// *

+// * Default is {@code 4096} +// * +// * @param length maximal number of characters +// * @return this builder +// */ +// @ConfiguredOption("4096") +// B maxInitialLineLength(int length); +// +// /** +// * Enable negotiation for gzip/deflate content encodings. Clients can +// * request compression using the "Accept-Encoding" header. +// *

+// * Default is {@code false} +// * +// * @param value compression flag +// * @return this builder +// */ +// @ConfiguredOption("false") +// B enableCompression(boolean value); +// +// /** +// * Set a maximum payload size for a client request. Can prevent DoS +// * attacks. +// * +// * @param size maximum payload size +// * @return this builder +// */ +// @ConfiguredOption +// B maxPayloadSize(long size); +// +// /** +// * Set a maximum length of the content of an upgrade request. +// *

+// * Default is {@code 64*1024} +// * +// * @param size Maximum length of the content of an upgrade request +// * @return this builder +// */ +// @ConfiguredOption("65536") +// B maxUpgradeContentLength(int size); +// +// /** +// * Update this socket configuration from a {@link io.helidon.config.Config}. +// * +// * @param config configuration on the node of a socket +// * @return updated builder instance +// */ +// @SuppressWarnings("unchecked") +// default B config(Config config) { +// config.get("port").asInt().ifPresent(this::port); +// config.get("bind-address").asString().ifPresent(this::host); +// config.get("backlog").asInt().ifPresent(this::backlog); +// config.get("max-header-size").asInt().ifPresent(this::maxHeaderSize); +// config.get("max-initial-line-length").asInt().ifPresent(this::maxInitialLineLength); +// config.get("max-payload-size").asInt().ifPresent(this::maxPayloadSize); +// +// DeprecatedConfig.get(config, "timeout-millis", "timeout") +// .asInt() +// .ifPresent(it -> this.timeout(it, TimeUnit.MILLISECONDS)); +// DeprecatedConfig.get(config, "receive-buffer-size", "receive-buffer") +// .asInt() +// .ifPresent(this::receiveBufferSize); +// +// Optional> enabledProtocols = DeprecatedConfig.get(config, "ssl.protocols", "ssl-protocols") +// .asList(String.class) +// .asOptional(); +// +// // tls +// Config sslConfig = DeprecatedConfig.get(config, "tls", "ssl"); +// if (sslConfig.exists()) { +// try { +// FakeWebServerTlsConfigBean.Builder builder = FakeWebServerTlsConfigBean.builder(); +// enabledProtocols.ifPresent(builder::enabledProtocols); +// builder.config(sslConfig); +// +// this.tls(builder.build()); +// } catch (IllegalStateException e) { +// throw new ConfigException("Cannot load SSL configuration.", e); +// } +// } +// +// // compression +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// return (B) this; +// } +// } +// +// /** +// * The {@link io.helidon.webserver.SocketConfiguration} builder class. +// */ +// @Configured +// final class Builder implements SocketConfigurationBuilder, io.helidon.common.Builder { +// /** +// * @deprecated remove once WebServer.Builder.addSocket(name, socket) methods are removed +// */ +// @Deprecated +// static final String UNCONFIGURED_NAME = "io.helidon.webserver.SocketConfiguration.UNCONFIGURED"; +// private final FakeWebServerTlsConfigBean.Builder tlsConfigBuilder = FakeWebServerTlsConfigBean.builder(); +// +// private int port = 0; +// private InetAddress bindAddress = null; +// private int backlog = DEFAULT_BACKLOG_SIZE; +// private int timeoutMillis = 0; +// private int receiveBufferSize = 0; +// private FakeWebServerTlsConfigBean webServerTls; +// // this is for backward compatibility, should be initialized to null once the +// // methods with `name` are removed from server builder (for adding sockets) +// private String name = UNCONFIGURED_NAME; +// private boolean enabled = true; +// // these values are as defined in Netty implementation +// private int maxHeaderSize = 8192; +// private int maxInitialLineLength = 4096; +// private int maxChunkSize = 8192; +// private boolean validateHeaders = true; +// private int initialBufferSize = 128; +// private boolean enableCompression = false; +// private long maxPayloadSize = -1; +// private int maxUpgradeContentLength = 64 * 1024; +// +// private Builder() { +// } +// +// @Override +// public FakeSocketConfigBean build() { +// if (null == webServerTls) { +// webServerTls = tlsConfigBuilder.build(); +// } +// +// if (null == name) { +// throw new ConfigException("Socket name must be configured for each socket"); +// } +// +// return new ServerBasicConfig.SocketConfig(this); +// } +// +// @Override +// public Builder port(int port) { +// this.port = port; +// return this; +// } +// +// @Override +// public Builder bindAddress(InetAddress bindAddress) { +// this.bindAddress = bindAddress; +// return this; +// } +// +// /** +// * Configures a maximum length of the queue of incoming connections on the server +// * socket. +// *

+// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. +// * +// * @param backlog a maximum length of the queue of incoming connections +// * @return this builder +// */ +// public Builder backlog(int backlog) { +// this.backlog = backlog; +// return this; +// } +// +// /** +// * Configures a server socket timeout in milliseconds or {@code 0} for an infinite timeout. +// * +// * @param timeoutMillis a server socket timeout in milliseconds or {@code 0} +// * @return this builder +// * +// * @deprecated since 2.0.0 please use {@link #timeout(long, java.util.concurrent.TimeUnit)} instead +// */ +// @Deprecated +// public Builder timeoutMillis(int timeoutMillis) { +// this.timeoutMillis = timeoutMillis; +// return this; +// } +// +// /** +// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the +// * server socket. +// *

+// * If {@code 0} then use implementation default. +// * +// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} +// * @return this builder +// */ +// @Override +// public Builder receiveBufferSize(int receiveBufferSize) { +// this.receiveBufferSize = receiveBufferSize; +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContext a SSL context to use +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link #tls(FakeWebServerTlsConfigBean)} instead +// */ +// @Deprecated +// public Builder ssl(SSLContext sslContext) { +// if (null != sslContext) { +// this.tlsConfigBuilder.sslContext(sslContext); +// } +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param sslContextBuilder a SSL context builder to use; will be built as a first step of this +// * method execution +// * @return this builder +// * @deprecated since 2.0.0, please use {@link #tls(Supplier)} instead +// */ +// @Deprecated +// public Builder ssl(Supplier sslContextBuilder) { +// return ssl(sslContextBuilder != null ? sslContextBuilder.get() : null); +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} enables the +// * default protocols +// * @return this builder +// * +// * @deprecated since 2.0.0, please use {@link FakeWebServerTlsConfigBean.Builder#enabledProtocols(String...)} +// * instead +// */ +// @Deprecated +// public Builder enabledSSlProtocols(String... protocols) { +// if (null == protocols) { +// enabledSSlProtocols(List.of()); +// } else { +// enabledSSlProtocols(Arrays.asList(protocols)); +// } +// return this; +// } +// +// /** +// * Configures the SSL protocols to enable with the server socket. +// * @param protocols protocols to enable, if {@code null} or empty enables +// * the default protocols +// * @return this builder +// */ +// @Deprecated +// public Builder enabledSSlProtocols(List protocols) { +// if (null == protocols) { +// this.tlsConfigBuilder.enabledProtocols(List.of()); +// } else { +// this.tlsConfigBuilder.enabledProtocols(protocols); +// } +// return this; +// } +// +// @Override +// public Builder timeout(long amount, TimeUnit unit) { +// long timeout = unit.toMillis(amount); +// if (timeout > Integer.MAX_VALUE) { +// this.timeoutMillis = 0; +// } else { +// this.timeoutMillis = (int) timeout; +// } +// return this; +// } +// +// @Override +// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { +// this.webServerTls = webServerTls; +// return this; +// } +// +// @Override +// public Builder maxHeaderSize(int size) { +// this.maxHeaderSize = size; +// return this; +// } +// +// @Override +// public Builder maxInitialLineLength(int length) { +// this.maxInitialLineLength = length; +// return this; +// } +// +// @Override +// public Builder maxPayloadSize(long size) { +// this.maxPayloadSize = size; +// return this; +// } +// +// @Override +// public Builder maxUpgradeContentLength(int size) { +// this.maxUpgradeContentLength = size; +// return this; +// } +// +// /** +// * Configure a socket name, to bind named routings to. +// * +// * @param name name of the socket +// * @return updated builder instance +// */ +// @ConfiguredOption(required = true) +// public Builder name(String name) { +// this.name = name; +// return this; +// } +// +// /** +// * Set this socket builder to enabled or disabled. +// * +// * @param enabled when set to {@code false}, the socket is not going to be opened by the server +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// return this; +// } +// +// /** +// * Configure maximal size of a chunk to be read from incoming requests. +// * Defaults to {@code 8192}. +// * +// * @param size maximal chunk size +// * @return updated builder instance +// */ +// public Builder maxChunkSize(int size) { +// this.maxChunkSize = size; +// return this; +// } +// +// /** +// * Configure whether to validate header names. +// * Defaults to {@code true} to make sure header names are valid strings. +// * +// * @param validate set to {@code false} to ignore header validation +// * @return updated builder instance +// */ +// public Builder validateHeaders(boolean validate) { +// this.validateHeaders = validate; +// return this; +// } +// +// /** +// * Configure initial size of the buffer used to parse HTTP line and headers. +// * Defaults to {@code 128}. +// * +// * @param size initial buffer size +// * @return updated builder instance +// */ +// public Builder initialBufferSize(int size) { +// this.initialBufferSize = size; +// return this; +// } +// +// /** +// * Configure whether to enable content negotiation for compression. +// * +// * @param value compression flag +// * @return updated builder instance +// */ +// public Builder enableCompression(boolean value) { +// this.enableCompression = value; +// return this; +// } +// +// @Override +// public Builder config(Config config) { +// SocketConfigurationBuilder.super.config(config); +// +// config.get("name").asString().ifPresent(this::name); +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("max-chunk-size").asInt().ifPresent(this::maxChunkSize); +// config.get("validate-headers").asBoolean().ifPresent(this::validateHeaders); +// config.get("initial-buffer-size").asInt().ifPresent(this::initialBufferSize); +// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); +// +// return this; +// } +// +// int port() { +// return port; +// } +// +// Optional bindAddress() { +// return Optional.ofNullable(bindAddress); +// } +// +// int backlog() { +// return backlog; +// } +// +// int timeoutMillis() { +// return timeoutMillis; +// } +// +// int receiveBufferSize() { +// return receiveBufferSize; +// } +// +// FakeWebServerTlsConfigBean tlsConfig() { +// return webServerTls; +// } +// +// String name() { +// return name; +// } +// +// boolean enabled() { +// return enabled; +// } +// +// int maxHeaderSize() { +// return maxHeaderSize; +// } +// +// int maxInitialLineLength() { +// return maxInitialLineLength; +// } +// +// int maxChunkSize() { +// return maxChunkSize; +// } +// +// boolean validateHeaders() { +// return validateHeaders; +// } +// +// int initialBufferSize() { +// return initialBufferSize; +// } +// +// boolean enableCompression() { +// return enableCompression; +// } +// +// long maxPayloadSize() { +// return maxPayloadSize; +// } +// +// int maxUpgradeContentLength() { +// return maxUpgradeContentLength; +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java new file mode 100644 index 00000000000..719ffc6b3e9 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java @@ -0,0 +1,128 @@ +/* + * 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.pico.builder.config.fakes.config; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanLogTracingConfig. + */ +@ConfigBean +public interface FakeSpanLogTracingConfig extends FakeTraceableConfig { +// /** +// * Disabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean DISABLED = FakeSpanLogTracingConfigBean.builder("disabled").enabled(false).build(); +// /** +// * Enabled traced span log. +// */ +// public static final FakeSpanLogTracingConfigBean ENABLED = FakeSpanLogTracingConfigBean.builder("enabled").build(); +// +// /** +// * A new span log. +// * @param name name of the span log +// */ +// protected FakeSpanLogTracingConfigBean(String name) { +// super(name); +// } +// + +// /** +// * Merge two traced span log configurations. +// * +// * @param older original configuration with default values +// * @param newer new configuration to override the older +// * @return a new traced span log mergint the older and newer +// */ +// static FakeSpanLogTracingConfigBean merge(FakeSpanLogTracingConfigBean older, FakeSpanLogTracingConfigBean newer) { +// return new FakeSpanLogTracingConfigBean(newer.name()) { +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Fluent API builder to create a new traced span log configuration. +// * +// * @param name name of the span log +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create a new traced span log configuration from {@link io.helidon.config.Config}. +// * +// * @param name name of the span log +// * @param config config for a traced span log +// * @return a new traced span log configuration +// */ +// public static FakeSpanLogTracingConfigBean create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link FakeSpanLogTracingConfigBean}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final String name; +// private Optional enabled = Optional.empty(); +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public FakeSpanLogTracingConfigBean build() { +// final Optional finalEnabled = enabled; +// return new FakeSpanLogTracingConfigBean(name) { +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// }; +// } +// +// /** +// * Configure whether this traced span log is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config config of a traced span log +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java new file mode 100644 index 00000000000..39a3e2a8130 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java @@ -0,0 +1,258 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Map; +import java.util.Optional; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka SpanTracingConfig. + * + * Configuration of a single traced span. + */ +@ConfigBean +public interface FakeSpanTracingConfig extends FakeTraceableConfig { + +// /** +// * A traced span that is disabled and all logs on it are disabled as well. +// */ +// public static final SpanTracingConfig DISABLED = SpanTracingConfig.builder("disabled").enabled(false).build(); +// /** +// * A traced span that is inabled and all logs on it are enabled as well. +// */ +// public static final SpanTracingConfig ENABLED = SpanTracingConfig.builder("enabled").build(); + +// /** +// * A new traceable span. +// * +// * @param name name of this span +// */ +// protected SpanTracingConfig(String name) { +// super(name); +// } +// +// @Override +// public String toString() { +// return "SpanTracingConfig(" + name() + ")"; +// } +// +// /** +// * Merge configuration of two traced spans. +// * +// * @param older older span with default values +// * @param newer newer span overriding values in older +// * @return a new merged traced span configuration +// */ +// static SpanTracingConfig merge(SpanTracingConfig older, SpanTracingConfig newer) { +// return new SpanTracingConfig(newer.name()) { +// @Override +// public Optional newName() { +// return newer.newName() +// .or(older::newName); +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// +// @Override +// public Optional getSpanLog(String name) { +// Optional newLog = newer.getSpanLog(name); +// Optional oldLog = older.getSpanLog(name); +// +// if (newLog.isPresent() && oldLog.isPresent()) { +// return Optional.of(SpanLogTracingConfig.merge(oldLog.get(), newLog.get())); +// } +// +// if (newLog.isPresent()) { +// return newLog; +// } +// +// return oldLog; +// } +// }; +// } + + /** + * When rename is desired, returns the new name. + * + * @return new name for this span or empty when rename is not desired + */ + Optional newName(); + +// /** +// * Configuration of a traced span log. +// * +// * @param name name of the log event +// * @return configuration of the log event, or empty if not explicitly configured (used when merging) +// */ +// protected abstract Optional getSpanLog(String name); + + @Singular("spanLog") // B addSpanLog(String, FakeSpanLogTracingConfigBean); + Map spanLogMap(); + +// /** +// * Configuration of a traceable span log. +// * If this span is disabled, the log is always disabled. +// * +// * @param name name of the log event +// * @return configuration of the log event +// */ +// public final SpanLogTracingConfig spanLog(String name) { +// if (enabled()) { +// return getSpanLog(name).orElse(SpanLogTracingConfig.ENABLED); +// } else { +// return SpanLogTracingConfig.DISABLED; +// } +// } +// +// /** +// * Whether a log event should be logged on the span with a default value. +// * +// * @param logName name of the log event +// * @param defaultValue to use in case the log event is not configured in this span's configuration +// * @return whether to log ({@code true}) the event or not ({@code false}), uses the default value for unconfigured logs +// */ +// public boolean logEnabled(String logName, boolean defaultValue) { +// if (enabled()) { +// return getSpanLog(logName).map(Traceable::enabled).orElse(defaultValue); +// } +// return false; +// } +// +// /** +// * A fluent API builder to create traced span configuration. +// * +// * @param name name of the span +// * @return a new builder instance +// */ +// public static Builder builder(String name) { +// return new Builder(name); +// } +// +// /** +// * Create traced span configuration from a {@link io.helidon.config.Config}. +// * +// * @param name name of the span +// * @param config config to load span configuration from +// * @return a new traced span configuration +// */ +// public static SpanTracingConfig create(String name, Config config) { +// return builder(name).config(config).build(); +// } +// +// /** +// * A fluent API builder for {@link SpanTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map spanLogMap = new HashMap<>(); +// private final String name; +// private Optional enabled = Optional.empty(); +// private String newName; +// +// private Builder(String name) { +// this.name = name; +// } +// +// @Override +// public SpanTracingConfig build() { +// final Map finalSpanLogMap = new HashMap<>(spanLogMap); +// final Optional finalNewName = Optional.ofNullable(newName); +// final Optional finalEnabled = enabled; +// +// return new SpanTracingConfig(name) { +// @Override +// public Optional newName() { +// return finalNewName; +// } +// +// @Override +// public Optional isEnabled() { +// return finalEnabled; +// } +// +// @Override +// protected Optional getSpanLog(String name) { +// if (enabled.orElse(true)) { +// return Optional.ofNullable(finalSpanLogMap.get(name)); +// } +// return Optional.of(SpanLogTracingConfig.DISABLED); +// } +// }; +// } +// +// /** +// * Configure whether this traced span is enabled or disabled. +// * +// * @param enabled if disabled, this span and all logs will be disabled +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// +// /** +// * Configure a new name of this span. +// * +// * @param newName new name to use when reporting this span +// * @return updated builder instance +// */ +// public Builder newName(String newName) { +// this.newName = newName; +// return this; +// } +// +// /** +// * Add configuration of a traced span log. +// * +// * @param spanLogTracingConfig configuration of the traced span log +// * @return updated builder instance +// */ +// public Builder addSpanLog(SpanLogTracingConfig spanLogTracingConfig) { +// this.spanLogMap.put(spanLogTracingConfig.name(), spanLogTracingConfig); +// return this; +// } +// +// /** +// * Update this builder from {@link io.helidon.config.Config}. +// * +// * @param config configuration of this span +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// config.get("new-name").asString().ifPresent(this::newName); +// config.get("logs") +// .asNodeList() +// .ifPresent(nodes -> { +// nodes.forEach(node -> { +// // name is mandatory +// addSpanLog(SpanLogTracingConfig.create(node.get("name").asString().get(), node)); +// }); +// }); +// +// return this; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java new file mode 100644 index 00000000000..ff675ee14f8 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java @@ -0,0 +1,56 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Optional; + +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka Traceable. + * + * Tracing configuration that can be enabled or disabled. + */ +@ConfigBean +public interface FakeTraceableConfig { + /** + * Whether this trace should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not, + * {@code empty} when this flag is not explicitly configured + */ + /*protected*/ Optional isEnabled(); + + /** + * Name of this traceable unit. + * + * @return name + */ + String name(); + + /** + * Whether this traceable should be executed or not. + * + * @return {@code true} if span/component should be traced, + * {@code false} if it should not + */ + default boolean enabled() { + return isEnabled().orElse(true); + } + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java new file mode 100644 index 00000000000..2e6c258f71b --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java @@ -0,0 +1,103 @@ +/* + * 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.pico.builder.config.fakes.config; + +/** + * Tracer abstraction. + * Tracer is the central point that collects tracing spans, and (probably) pushes them to backend. + */ +public interface FakeTracer { +// /** +// * Create a no-op tracer. All spans created from this tracer are not doing anything. +// * +// * @return no-op tracer +// */ +// static Tracer noOp() { +// return NoOpTracer.instance(); +// } +// +// /** +// * Get the currently registered global tracer. +// * +// * @return global tracer +// */ +// static Tracer global() { +// return TracerProviderHelper.global(); +// } +// +// /** +// * Register a global tracer, behavior depends on implementation. +// * +// * @param tracer tracer to use as a global tracer +// */ +// +// static void global(Tracer tracer) { +// TracerProviderHelper.global(tracer); +// } +// +// /** +// * Whether this tracer is enabled or not. +// * A no op tracer is disabled. +// * +// * @return {@code true} if this tracer is enabled +// */ +// boolean enabled(); +// +// /** +// * A new span builder to construct {@link io.helidon.tracing.Span}. +// * +// * @param name name of the operation +// * @return a new span builder +// */ +// Span.Builder spanBuilder(String name); +// +// /** +// * Extract parent span context from inbound request, such as from HTTP headers. +// * +// * @param headersProvider provider of headers +// * @return span context of inbound parent span, or empty optional if no span context can be found +// */ +// Optional extract(HeaderProvider headersProvider); +// +// /** +// * Inject current span as a parent for outbound request, such as when invoking HTTP request from a client. +// * +// * @param spanContext current span context +// * @param inboundHeadersProvider provider of inbound headers, may be {@link HeaderProvider#empty()} or headers from original +// * request (if any) +// * @param outboundHeadersConsumer consumer of headers that should be propagated to remote endpoint +// */ +// void inject(SpanContext spanContext, HeaderProvider inboundHeadersProvider, HeaderConsumer outboundHeadersConsumer); +// +// /** +// * Access the underlying tracer by specific type. +// * This is a dangerous operation that will succeed only if the tracer is of expected type. This practically +// * removes abstraction capabilities of this API. +// * +// * @param tracerClass type to access +// * @return instance of the tracer +// * @param type of the tracer +// * @throws java.lang.IllegalArgumentException in case the tracer cannot provide the expected type +// */ +// default T unwrap(Class tracerClass) { +// try { +// return tracerClass.cast(this); +// } catch (ClassCastException e) { +// throw new IllegalArgumentException("This tracer is not compatible with " + tracerClass.getName()); +// } +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java new file mode 100644 index 00000000000..9515df93034 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java @@ -0,0 +1,244 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Map; + +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka TracingConfig. + * + * Tracing configuration that contains traced components (such as WebServer, Security) and their traced spans and span logs. + * Spans can be renamed through configuration, components, spans and span logs may be disabled through this configuration. + */ +@ConfigBean(key = "tracing") +public interface FakeTracingConfig extends FakeTraceableConfig { +// /** +// * Traced config that is enabled for all components, spans and logs. +// */ +// FakeTracingConfig ENABLED = FakeTracingConfig.builder().build(); +// /** +// * Traced conifg that is disabled for all components, spans and logs. +// */ +// FakeTracingConfig DISABLED = FakeTracingConfig.builder().enabled(false).build(); + +// /** +// * A new traced configuration. +// * +// * @param name name of this configuration, when created using {@link FakeTracingConfig.Builder}, +// * the name is {@code helidon} +// */ +// protected FakeTracingConfig(String name) { +// super(name); +// } +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration or empty if defaults should be used +// */ +// protected abstract Optional getComponent(String componentName); +// +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @return component tracing configuration if configured, or an enabled component configuration +// */ +// public ComponentTracingConfig component(String componentName) { +// return component(componentName, true); +// } + + @Singular("component") // Builder::addComponent(String component); Impl::getComponent(String component); + Map components(); + +// /** +// * Configuration of a traced component. +// * +// * @param componentName name of the component +// * @param enabledByDefault whether the component should be enabled or disabled in case it is not configured +// * @return component tracing configuration if configured, or an enabled/disabled component configuration depending on +// * {@code enabledByDefault} +// */ +// public ComponentTracingConfig component(String componentName, boolean enabledByDefault) { +// if (enabled()) { +// return getComponent(componentName) +// .orElseGet(() -> enabledByDefault ? ComponentTracingConfig.ENABLED : ComponentTracingConfig.DISABLED); +// } +// +// return ComponentTracingConfig.DISABLED; +// } +// +// @Override +// public String toString() { +// return "TracingConfig(" + name() + ")"; +// } +// +// /** +// * Create new tracing configuration based on the provided config. +// * +// * @param config configuration of tracing +// * @return tracing configuration +// */ +// public static FakeTracingConfig create(Config config) { +// return builder().config(config).build(); +// } +// +// /** +// * A fluent API builder for tracing configuration. +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Merge two configurations together. +// * The result will combine configuration from both configurations. In case +// * of conflicts, the {@code newer} wins. +// * +// * @param older older instance to merge +// * @param newer newer (more significant) instance to merge +// * @return a new configuration combining odler and newer +// */ +// public static FakeTracingConfig merge(FakeTracingConfig older, FakeTracingConfig newer) { +// return new FakeTracingConfig(newer.name()) { +// @Override +// public Optional getComponent(String componentName) { +// Optional newerComponent = newer.getComponent(componentName); +// Optional olderComponent = older.getComponent(componentName); +// +// // both configured +// if (newerComponent.isPresent() && olderComponent.isPresent()) { +// return Optional.of(ComponentTracingConfig.merge(olderComponent.get(), newerComponent.get())); +// } +// +// // only newer configured +// if (newerComponent.isPresent()) { +// return newerComponent; +// } +// +// // only older configured +// return olderComponent; +// } +// +// @Override +// public Optional isEnabled() { +// return newer.isEnabled() +// .or(older::isEnabled); +// } +// }; +// } +// +// /** +// * Return configuration of a specific span. +// * This is a shortcut method to {@link #component(String)} and +// * {@link ComponentTracingConfig#span(String)}. +// * +// * @param component component, such as "web-server", "security" +// * @param spanName name of the span, such as "HTTP Request", "security:atn" +// * @return configuration of the span if present in this traced system configuration +// */ +// public SpanTracingConfig spanConfig(String component, String spanName) { +// return component(component).span(spanName); +// } + +// /** +// * Fluent API builder for {@link FakeTracingConfig}. +// */ +// public static final class Builder implements io.helidon.common.Builder { +// private final Map components = new HashMap<>(); +// private Optional enabled = Optional.empty(); +// +// private Builder() { +// } +// +// @Override +// public FakeTracingConfig build() { +// return new RootTracingConfig("helidon", new HashMap<>(components), enabled); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config Config with tracing configuration +// * @return updated builder instance +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// Config compConfig = config.get("components"); +// compConfig.asNodeList() +// .ifPresent(compList -> { +// compList.forEach(componentConfig -> addComponent(ComponentTracingConfig.create(componentConfig.name(), +// componentConfig))); +// }); +// +// return this; +// } +// +// /** +// * Add a traced component configuration. +// * +// * @param component configuration of this component's tracing +// * @return updated builder instance +// */ +// public Builder addComponent(ComponentTracingConfig component) { +// components.put(component.name(), component); +// return this; +// } +// +// /** +// * Whether overall tracing is enabled. +// * If tracing is disabled on this level, all traced components and spans are disabled - even if explicitly configured +// * as enabled. +// * +// * @param enabled set to {@code false} to disable tracing for any component and span +// * @return updated builder instance +// */ +// public Builder enabled(boolean enabled) { +// this.enabled = Optional.of(enabled); +// return this; +// } +// } +// +// static final class RootTracingConfig extends FakeTracingConfig { +// private final Map components; +// private final Optional enabled; +// +// RootTracingConfig(String name, +// Map components, +// Optional enabled) { +// super(name); +// this.components = components; +// this.enabled = enabled; +// } +// +// @Override +// public Optional getComponent(String componentName) { +// return Optional.ofNullable(components.get(componentName)); +// } +// +// @Override +// public Optional isEnabled() { +// return enabled; +// } +// +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java new file mode 100644 index 00000000000..5f1213c1484 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java @@ -0,0 +1,438 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.security.SecureRandom; +import java.util.Collection; +import java.util.Random; +import java.util.Set; + +import javax.net.ssl.SSLContext; + +import io.helidon.common.LazyValue; +import io.helidon.pico.builder.Singular; +import io.helidon.pico.builder.config.ConfigBean; + +/** + * aka WebServerTls. + * + * A class wrapping transport layer security (TLS) configuration for + * WebServer sockets. + */ +@ConfigBean +public interface FakeWebServerTlsConfig { + String PROTOCOL = "TLS"; + // secure random cannot be stored in native image, it must be initialized at runtime + LazyValue RANDOM = LazyValue.create(SecureRandom::new); + + /** + * This constant is a context classifier for the x509 client certificate if it is present. Callers may use this + * constant to lookup the client certificate associated with the current request context. + */ + String CLIENT_X509_CERTIFICATE = FakeWebServerTlsConfig.class.getName() + ".client-x509-certificate"; + +// private final Set enabledTlsProtocols; +// private final Set cipherSuite; +// private final SSLContext sslContext; +// private final boolean enabled; +// private final ClientAuthentication clientAuth; +// +// private FakeWebServerTlsConfigBean(Builder builder) { +// this.enabledTlsProtocols = Set.copyOf(builder.enabledTlsProtocols); +// this.cipherSuite = builder.cipherSuite; +// this.sslContext = builder.sslContext; +// this.enabled = (null != sslContext); +// this.clientAuth = builder.clientAuth; +// } +// +// /** +// * A fluent API builder for {@link FakeWebServerTlsConfigBean}. +// * +// * @return a new builder instance +// */ +// public static Builder builder() { +// return new Builder(); +// } +// +// /** +// * Create TLS configuration from config. +// * +// * @param config located on the node of the tls configuration (usually this is {@code ssl}) +// * @return a new TLS configuration +// */ +// public static FakeWebServerTlsConfigBean create(Config config) { +// return builder().config(config).build(); +// } +// + + Collection enabledTlsProtocols(); +// { +// return enabledTlsProtocols; +// } +// + + SSLContext sslContext(); +// { +// return sslContext; +// } + +// ClientAuthentication clientAuth() { +// return clientAuth; +// } + + @Singular("cipher") + Set cipherSuite(); +// { +// return cipherSuite; +// } + + /** + * Whether this TLS config has security enabled (and the socket is going to be + * protected by one of the TLS protocols), or no (and the socket is going to be plain). + * + * @return {@code true} if this configuration represents a TLS configuration, {@code false} for plain configuration + */ + boolean enabled(); +// { +// return enabled; +// } +// +// /** +// * Fluent API builder for {@link FakeWebServerTlsConfigBean}. +// */ +// @Configured +// public static class Builder implements io.helidon.common.Builder { +// private final Set enabledTlsProtocols = new HashSet<>(); +// +// private SSLContext sslContext; +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeoutSeconds; +// +// private boolean enabled; +// private Boolean explicitEnabled; +// private ClientAuthentication clientAuth; +// private Set cipherSuite = Set.of(); +// +// private Builder() { +// clientAuth = ClientAuthentication.NONE; +// } +// +// @Override +// public FakeWebServerTlsConfigBean build() { +// boolean enabled; +// +// if (null == explicitEnabled) { +// enabled = this.enabled; +// } else { +// enabled = explicitEnabled; +// } +// +// if (!enabled) { +// this.sslContext = null; +// // ssl is disabled +// return new FakeWebServerTlsConfigBean(this); +// } +// +// if (null == sslContext) { +// // no explicit ssl context, build it using private key and trust store +// sslContext = newSSLContext(); +// } +// +// return new FakeWebServerTlsConfigBean(this); +// } +// +// /** +// * Update this builder from configuration. +// * +// * @param config config on the node of SSL configuration +// * @return this builder +// */ +// public Builder config(Config config) { +// config.get("enabled").asBoolean().ifPresent(this::enabled); +// +// if (explicitEnabled != null && !explicitEnabled) { +// return this; +// } +// +// config.get("client-auth").asString().ifPresent(this::clientAuth); +// config.get("private-key") +// .ifExists(it -> privateKey(FakeKeyConfig.create(it))); +// +// config.get("trust") +// .ifExists(it -> trust(FakeKeyConfig.create(it))); +// +// config.get("protocols").asList(String.class).ifPresent(this::enabledProtocols); +// config.get("session-cache-size").asLong().ifPresent(this::sessionCacheSize); +// config.get("cipher-suite").asList(String.class).ifPresent(this::allowedCipherSuite); +// DeprecatedConfig.get(config, "session-timeout-seconds", "session-timeout") +// .asLong() +// .ifPresent(this::sessionTimeoutSeconds); +// +// return this; +// } +// +// private void clientAuth(String it) { +// clientAuth(ClientAuthentication.valueOf(it.toUpperCase())); +// } +// +// /** +// * Configures whether client authentication will be required or not. +// * +// * @param clientAuth client authentication +// * @return this builder +// */ +// @ConfiguredOption("none") +// public Builder clientAuth(ClientAuthentication clientAuth) { +// this.clientAuth = Objects.requireNonNull(clientAuth); +// return this; +// } +// +// /** +// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then +// * the server enforces an SSL communication. +// * +// * @param context a SSL context to use +// * @return this builder +// */ +// public Builder sslContext(SSLContext context) { +// this.enabled = true; +// this.sslContext = context; +// return this; +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * @param protocols protocols to enable, if empty, enables defaults +// * +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(String... protocols) { +// return enabledProtocols(Arrays.asList(Objects.requireNonNull(protocols))); +// } +// +// /** +// * Configures the TLS protocols to enable with the server socket. +// * +// * @param protocols protocols to enable, if empty enables +// * the default protocols +// * @return this builder +// * @throws java.lang.NullPointerException in case the protocols is null +// */ +// public Builder enabledProtocols(Collection protocols) { +// Objects.requireNonNull(protocols); +// +// this.enabledTlsProtocols.clear(); +// this.enabledTlsProtocols.addAll(protocols); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// @ConfiguredOption(required = true) +// public Builder privateKey(FakeKeyConfig privateKeyConfig) { +// // setting private key, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.privateKeyConfig = Objects.requireNonNull(privateKeyConfig); +// return this; +// } +// +// /** +// * Configure private key to use for SSL context. +// * +// * @param privateKeyConfigBuilder the required private key configuration parameter +// * @return this builder +// */ +// public Builder privateKey(Supplier privateKeyConfigBuilder) { +// return privateKey(privateKeyConfigBuilder.get()); +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return this builder +// */ +// @ConfiguredOption +// public Builder trust(FakeKeyConfig trustConfig) { +// // setting explicit trust, need to reset ssl context +// this.enabled = true; +// this.sslContext = null; +// this.trustConfig = Objects.requireNonNull(trustConfig); +// return this; +// } +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfigBuilder the trust configuration builder +// * @return this builder +// */ +// public Builder trust(Supplier trustConfigBuilder) { +// return trust(trustConfigBuilder.get()); +// } +// +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return this builder +// */ +// @ConfiguredOption +// public Builder sessionTimeoutSeconds(long sessionTimeout) { +// this.sessionTimeoutSeconds = sessionTimeout; +// return this; +// } +// +// /** +// * Set the timeout for the cached SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param timeout the session timeout amount +// * @param unit the session timeout time unit +// * @return this builder +// */ +// public Builder sessionTimeout(long timeout, TimeUnit unit) { +// this.sessionTimeoutSeconds = unit.toSeconds(timeout); +// return this; +// } +// +// /** +// * Set allowed cipher suite. If an empty collection is set, an exception is thrown since +// * it is required to support at least some ciphers. +// * +// * @param cipherSuite allowed cipher suite +// * @return an updated builder +// */ +// @ConfiguredOption(key = "cipher-suite") +// public Builder allowedCipherSuite(List cipherSuite) { +// Objects.requireNonNull(cipherSuite); +// if (cipherSuite.isEmpty()) { +// throw new IllegalStateException("Allowed cipher suite has to have at least one cipher specified"); +// } +// this.cipherSuite = Set.copyOf(cipherSuite); +// return this; +// } +// +// /** +// * Whether the TLS config should be enabled or not. +// * +// * @param enabled configure to {@code false} to disable SSL context (and SSL support on the server) +// * @return this builder +// */ +// @ConfiguredOption(description = "Can be used to disable TLS even if keys are configured.", value = "true") +// public Builder enabled(boolean enabled) { +// this.enabled = enabled; +// this.explicitEnabled = enabled; +// return this; +// } +// +// private SSLContext newSSLContext() { +// try { +// if (null == privateKeyConfig) { +// throw new IllegalStateException("Private key must be configured when SSL is enabled."); +// } +// KeyManagerFactory kmf = buildKmf(this.privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(this.trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (this.sessionTimeoutSeconds > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeoutSeconds, Integer.MAX_VALUE)); +// } +// return ctx; +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Failed to build server SSL Context!", e); +// } +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.get().nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +// } +// +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java new file mode 100644 index 00000000000..c674fed80e4 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java @@ -0,0 +1,201 @@ +/* + * 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.pico.builder.config.fakes.config; + +import java.util.Random; + +import io.helidon.pico.builder.Builder; + +/** + * aka SSLContextBuilder. + */ +@Builder +public interface SSLContextConfig { + + String PROTOCOL = "TLS"; + Random RANDOM = new Random(); + +// private FakeKeyConfig privateKeyConfig; +// private FakeKeyConfig trustConfig; +// private long sessionCacheSize; +// private long sessionTimeout; +// +// private SSLContextConfig() { +// } +// + +// /** +// * Creates a builder of the {@link javax.net.ssl.SSLContext}. +// * +// * @param privateKeyConfig the required private key configuration parameter +// * @return this builder +// */ +// public static SSLContextConfig create(FakeKeyConfig privateKeyConfig) { +// return new SSLContextConfig().privateKeyConfig(privateKeyConfig); +// } + +// /** +// * Creates {@link javax.net.ssl.SSLContext} from the provided configuration. +// * +// * @param sslConfig the ssl configuration +// * @return a built {@link javax.net.ssl.SSLContext} +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// static SSLContext create(Config sslConfig) { +// return new SSLContextConfig().privateKeyConfig(FakeKeyConfig.create(sslConfig.get("private-key"))) +// .sessionCacheSize(sslConfig.get("session-cache-size").asInt().orElse(0)) +// .sessionTimeout(sslConfig.get("session-timeout").asInt().orElse(0)) +// .trustConfig(FakeKeyConfig.create(sslConfig.get("trust"))) +// .build(); +// } +// +// private SSLContextConfig privateKeyConfig(FakeKeyConfig privateKeyConfig) { +// this.privateKeyConfig = privateKeyConfig; +// return this; +// } + + FakeKeyConfig privateKeyConfig(); + +// +// /** +// * Set the trust key configuration to be used to validate certificates. +// * +// * @param trustConfig the trust configuration +// * @return an updated builder +// */ +// public SSLContextConfig trustConfig(FakeKeyConfig trustConfig) { +// this.trustConfig = trustConfig; +// return this; +// } + + FakeKeyConfig trustConfig(); + +// /** +// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the +// * default value. +// * +// * @param sessionCacheSize the session cache size +// * @return an updated builder +// */ +// public SSLContextConfig sessionCacheSize(long sessionCacheSize) { +// this.sessionCacheSize = sessionCacheSize; +// return this; +// } + + long sessionCacheSize(); + +// /** +// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the +// * default value. +// * +// * @param sessionTimeout the session timeout +// * @return an updated builder +// */ +// public SSLContextConfig sessionTimeout(long sessionTimeout) { +// this.sessionTimeout = sessionTimeout; +// return this; +// } + + long sessionTimeout(); + +// /** +// * Create new {@code {@link javax.net.ssl.SSLContext}} instance with configured settings. +// * +// * @return the SSL Context built instance +// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or +// * a {@link java.security.GeneralSecurityException} +// */ +// public SSLContext build() { +// Objects.requireNonNull(privateKeyConfig, "The private key config must be set!"); +// +// try { +// return newSSLContext(privateKeyConfig, trustConfig, sessionCacheSize, sessionTimeout); +// } catch (IOException | GeneralSecurityException e) { +// throw new IllegalStateException("Building of the SSLContext of unsuccessful!", e); +// } +// } + +// private static SSLContext newSSLContext(FakeKeyConfig privateKeyConfig, +// FakeKeyConfig trustConfig, +// long sessionCacheSize, +// long sessionTimeout) +// throws IOException, GeneralSecurityException { +// KeyManagerFactory kmf = buildKmf(privateKeyConfig); +// TrustManagerFactory tmf = buildTmf(trustConfig); +// +// // Initialize the SSLContext to work with our key managers. +// SSLContext ctx = SSLContext.getInstance(PROTOCOL); +// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); +// +// SSLSessionContext sessCtx = ctx.getServerSessionContext(); +// if (sessionCacheSize > 0) { +// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); +// } +// if (sessionTimeout > 0) { +// sessCtx.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE)); +// } +// return ctx; +// } +// +// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { +// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); +// if (algorithm == null) { +// algorithm = "SunX509"; +// } +// +// byte[] passwordBytes = new byte[64]; +// RANDOM.nextBytes(passwordBytes); +// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// ks.setKeyEntry("key", +// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), +// password, +// privateKeyConfig.certChain().toArray(new Certificate[0])); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); +// kmf.init(ks, password); +// +// return kmf; +// } +// +// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) +// throws IOException, GeneralSecurityException { +// List certs; +// +// if (trustConfig == null) { +// certs = List.of(); +// } else { +// certs = trustConfig.certs(); +// } +// +// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); +// ks.load(null, null); +// +// int i = 1; +// for (X509Certificate cert : certs) { +// ks.setCertificateEntry(String.valueOf(i), cert); +// i++; +// } +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(ks); +// return tmf; +// } +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java new file mode 100644 index 00000000000..2636622a275 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java @@ -0,0 +1,36 @@ +/* + * 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.pico.builder.config.test.testsubjects; + +import java.util.Map; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.testsubjects.CommonConfig; + +@ConfigBean(drivesActivation = false) +public interface ClientConfig extends CommonConfig { + + @ConfiguredOption("default") + @Override + String name(); + + int serverPort(); + + Map headers(); + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java new file mode 100644 index 00000000000..8c6d70d2d86 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java @@ -0,0 +1,36 @@ +/* + * 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.pico.builder.config.testsubjects; + +import java.util.List; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; + +@ConfigBean +public interface CommonConfig { + + String name(); + + @ConfiguredOption(required = true) + int port(); + + List cipherSuites(); + + char[] pwd(); + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java new file mode 100644 index 00000000000..9dcd7bf600e --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java @@ -0,0 +1,33 @@ +/* + * 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.pico.builder.config.testsubjects; + +import java.util.Optional; + +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.pico.builder.config.ConfigBean; + +@ConfigBean(atLeastOne = true) +public interface ServerConfig extends CommonConfig { + + @ConfiguredOption("default") + @Override + String name(); + + Optional description(); + +} diff --git a/pico/builder-config/tests/configbean/src/main/java/module-info.java b/pico/builder-config/tests/configbean/src/main/java/module-info.java new file mode 100644 index 00000000000..0db7b6f92a7 --- /dev/null +++ b/pico/builder-config/tests/configbean/src/main/java/module-info.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +/** + * Pico ConfigBean Builder test module. + */ +module io.helidon.pico.builder.config.tests.test.config { + requires static jakarta.inject; + requires static jakarta.annotation; + + requires static io.helidon.config.metadata; + + requires io.helidon.common; + requires io.helidon.common.config; + requires io.helidon.pico; + requires io.helidon.pico.builder.config; + requires io.helidon.pico.builder; +} diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java new file mode 100644 index 00000000000..f66904e5e6a --- /dev/null +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java @@ -0,0 +1,71 @@ +/* + * 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.pico.builder.config.test; + +import java.util.Map; + +import io.helidon.config.Config; +import io.helidon.config.ConfigSources; +import io.helidon.pico.builder.config.testsubjects.DefaultServerConfig; +import io.helidon.pico.builder.config.testsubjects.ServerConfig; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +class BasicConfigBeanTest { + + @Test + void acceptConfig() { + Config cfg = Config.create( + ConfigSources.create( + Map.of("name", "server", + "port", "8080", + "description", "test", + "pwd", "pwd1" +// , "cipher-suites", "a,b,c" // no List mapper available --- discuss w/ tlanger + ), + "my-simple-config-1")); + ServerConfig serverConfig = DefaultServerConfig.toBuilder(cfg).build(); + + assertThat(serverConfig.description(), optionalValue(equalTo("test"))); + assertThat(serverConfig.name(), equalTo("server")); + assertThat(serverConfig.port(), equalTo(8080)); +// assertThat(serverConfig.cipherSuites(), hasSize(3)); +// assertThat(serverConfig.cipherSuites(), contains("a", "b", "c")); + assertThat(new String(serverConfig.pwd()), equalTo("pwd1")); + assertThat(serverConfig.toString(), + startsWith("ServerConfig")); + assertThat(serverConfig.toString(), + endsWith("(name=server, port=8080, cipherSuites=[], pwd=not-null, description=Optional[test])")); + } + + @Test + void emptyConfig() { + Config cfg = Config.create(); + ServerConfig serverConfig = DefaultServerConfig.toBuilder(cfg).build(); + assertThat(serverConfig.description(), optionalEmpty()); + assertThat(serverConfig.name(), equalTo("default")); + assertThat(serverConfig.port(), equalTo(0)); + } + +} diff --git a/pico/builder-config/tests/pom.xml b/pico/builder-config/tests/pom.xml new file mode 100644 index 00000000000..c1397a3b1d1 --- /dev/null +++ b/pico/builder-config/tests/pom.xml @@ -0,0 +1,49 @@ + + + + + + io.helidon.pico.builder.config + helidon-pico-builder-config-project + 4.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + + true + true + true + true + true + true + + + io.helidon.pico.builder.config.tests + helidon-pico-builder-config-tests-project + Helidon Pico Builder Config Tests Project + pom + + + configbean + + + diff --git a/pico/builder/pom.xml b/pico/builder/pom.xml index 4d940e94523..9baea8f15fe 100644 --- a/pico/builder/pom.xml +++ b/pico/builder/pom.xml @@ -36,6 +36,11 @@ Helidon Pico Builder Project pom + + + 11 + + builder processor-spi diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java index 2490962c40c..5fcc2c02857 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java @@ -44,6 +44,8 @@ * Represents the context of the body being code generated. */ public class BodyContext { + static final String TAG_META_PROPS = "__META_PROPS"; + private final boolean doingConcreteType; private final TypeName implTypeName; private final TypeInfo typeInfo; @@ -109,7 +111,7 @@ public class BodyContext { * * @return true if we are processing the concrete type */ - protected boolean doingConcreteType() { + public boolean doingConcreteType() { return doingConcreteType; } @@ -118,7 +120,7 @@ protected boolean doingConcreteType() { * * @return the type name */ - protected TypeName implTypeName() { + public TypeName implTypeName() { return implTypeName; } @@ -127,7 +129,7 @@ protected TypeName implTypeName() { * * @return the type info */ - protected TypeInfo typeInfo() { + public TypeInfo typeInfo() { return typeInfo; } @@ -136,7 +138,7 @@ protected TypeInfo typeInfo() { * * @return the builder annotation */ - protected AnnotationAndValue builderAnnotation() { + public AnnotationAndValue builderAnnotation() { return builderAnnotation; } @@ -154,7 +156,7 @@ protected Map map() { * * @return the list of type elements */ - protected List allTypeInfos() { + public List allTypeInfos() { return allTypeInfos; } @@ -163,7 +165,7 @@ protected List allTypeInfos() { * * @return the list of attribute names */ - protected List allAttributeNames() { + public List allAttributeNames() { return allAttributeNames; } @@ -172,7 +174,7 @@ protected List allAttributeNames() { * * @return the parent type name */ - protected AtomicReference parentTypeName() { + public AtomicReference parentTypeName() { return parentTypeName; } @@ -235,7 +237,7 @@ protected boolean isBeanStyleRequired() { * * @return the list type */ - protected String listType() { + public String listType() { return listType; } @@ -244,7 +246,7 @@ protected String listType() { * * @return the map type */ - protected String mapType() { + public String mapType() { return mapType; } @@ -253,7 +255,7 @@ protected String mapType() { * * @return the set type */ - protected String setType() { + public String setType() { return setType; } @@ -262,7 +264,7 @@ protected String setType() { * * @return true if current has parent */ - protected boolean hasParent() { + public boolean hasParent() { return hasParent; } @@ -280,7 +282,7 @@ protected TypeName ctorBuilderAcceptTypeName() { * * @return the generic declaration */ - protected String genericBuilderClassDecl() { + public String genericBuilderClassDecl() { return genericBuilderClassDecl; } diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java index ee0d93719bb..a8619701068 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java @@ -48,6 +48,7 @@ import io.helidon.pico.types.TypeName; import io.helidon.pico.types.TypedElementName; +import static io.helidon.pico.builder.processor.tools.BodyContext.TAG_META_PROPS; import static io.helidon.pico.builder.processor.tools.BodyContext.toBeanAttributeName; /** @@ -200,6 +201,7 @@ protected String toBody(BodyContext ctx) { appendExtraMethods(builder, ctx); appendToBuilderMethods(builder, ctx); appendBuilder(builder, ctx); + appendExtraBuilderMethods(builder, ctx); appendExtraInnerClasses(builder, ctx); appendFooter(builder, ctx); return builder.toString(); @@ -208,11 +210,11 @@ protected String toBody(BodyContext ctx) { /** * Appends the footer of the generated class. * - * @param builder the builder - * @param ignoredCtx the context + * @param builder the builder + * @param ctx the context */ protected void appendFooter(StringBuilder builder, - BodyContext ignoredCtx) { + BodyContext ctx) { builder.append("}\n"); } @@ -271,8 +273,7 @@ protected void appendMetaAttributes(StringBuilder builder, builder.append("\t\tMap> metaProps = new java.util.LinkedHashMap<>();\n"); AtomicBoolean needsCustomMapOf = new AtomicBoolean(); - appendMetaProps(builder, "metaProps", - ctx.typeInfo(), ctx.map(), ctx.allAttributeNames(), ctx.allTypeInfos(), needsCustomMapOf); + appendMetaProps(builder, ctx, "metaProps", needsCustomMapOf); builder.append("\t\treturn metaProps;\n"); builder.append("\t}\n\n"); @@ -301,7 +302,7 @@ protected void appendFields(StringBuilder builder, String beanAttributeName = ctx.allAttributeNames().get(i); appendAnnotations(builder, method.annotations(), "\t"); builder.append("\tprivate "); - builder.append(getFieldModifier()); + builder.append(fieldModifier()); builder.append(toGenerics(method, false)).append(" "); builder.append(beanAttributeName).append(";\n"); } @@ -346,6 +347,11 @@ protected void appendHeader(StringBuilder builder, } else { if (ctx.hasParent()) { builder.append(toAbstractImplTypeName(ctx.parentTypeName().get(), ctx.builderAnnotation()).get()); + } else { + Optional baseExtendsTypeName = baseExtendsTypeName(ctx); + if (baseExtendsTypeName.isPresent()) { + builder.append(" extends ").append(baseExtendsTypeName.get().fqName()).append("\n\t\t\t\t\t\t\t\t\t\t"); + } } if (!ctx.hasParent() && ctx.hasStreamSupportOnImpl()) { @@ -357,11 +363,54 @@ protected void appendHeader(StringBuilder builder, if (!ctx.hasParent() && ctx.hasStreamSupportOnImpl()) { builder.append(", Supplier<").append(ctx.genericBuilderAcceptAliasDecl()).append(">"); } + + List extraImplementContracts = extraImplementedTypeNames(ctx); + extraImplementContracts.forEach(t -> builder.append(",\n\t\t\t\t\t\t\t\t\t\t\t").append(t.fqName())); } builder.append(" {\n"); } + /** + * Returns any extra 'extends' type name that should be on the main generated type at the base level. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected Optional baseExtendsTypeName(BodyContext ctx) { + return Optional.empty(); + } + + /** + * Returns any extra 'extends' type name that should be on the main generated builder type at the base level. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected Optional baseExtendsBuilderTypeName(BodyContext ctx) { + return Optional.empty(); + } + + /** + * Returns any extra 'implements' contract types that should be on the main generated type. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected List extraImplementedTypeNames(BodyContext ctx) { + return List.of(); + } + + /** + * Returns any extra 'implements' contract types that should be on the main generated builder type. + * + * @param ctx the context + * @return extra contracts implemented + */ + protected List extraImplementedBuilderContracts(BodyContext ctx) { + return List.of(); + } + /** * Adds extra imports to the generated builder. * @@ -400,10 +449,26 @@ protected void appendToStringMethod(StringBuilder builder, builder.append("\t@Override\n"); builder.append("\tpublic String toString() {\n"); builder.append("\t\treturn ").append(ctx.typeInfo().typeName()); - builder.append(".class.getSimpleName() + \"(\" + toStringInner() + \")\";\n"); + builder.append(".class.getSimpleName() + "); + + String instanceIdRef = instanceIdRef(ctx); + if (!instanceIdRef.isBlank()) { + builder.append("\"{\" + ").append(instanceIdRef).append(" + \"}\" + "); + } + builder.append("\"(\" + toStringInner() + \")\";\n"); builder.append("\t}\n\n"); } + /** + * The nuanced instance id for the {@link #appendToStringMethod(StringBuilder, BodyContext)}. + * + * @param ctx the context + * @return the instance id + */ + protected String instanceIdRef(BodyContext ctx) { + return ""; + } + /** * Adds extra methods to the generated builder. This base implementation will generate the visitAttributes() for the main * generated class. @@ -414,7 +479,7 @@ protected void appendToStringMethod(StringBuilder builder, protected void appendExtraMethods(StringBuilder builder, BodyContext ctx) { if (ctx.includeMetaAttributes()) { - appendVisitAttributes(builder, "", false, ctx); + appendVisitAttributes(builder, ctx, "", false); } } @@ -427,7 +492,7 @@ protected void appendExtraMethods(StringBuilder builder, */ protected void appendExtraInnerClasses(StringBuilder builder, BodyContext ctx) { - GenerateVisitor.appendAttributeVisitors(builder, ctx); + GenerateVisitorSupport.appendExtraInnerClasses(builder, ctx); } /** @@ -435,7 +500,7 @@ protected void appendExtraInnerClasses(StringBuilder builder, * * @return the field modifier */ - protected String getFieldModifier() { + protected String fieldModifier() { return "final "; } @@ -443,15 +508,19 @@ protected String getFieldModifier() { * Appends the visitAttributes() method on the generated class. * * @param builder the builder + * @param ctx the context * @param extraTabs spacing * @param beanNameRef refer to bean name? otherwise refer to the element name - * @param ctx the context */ protected void appendVisitAttributes(StringBuilder builder, + BodyContext ctx, String extraTabs, - boolean beanNameRef, - BodyContext ctx) { - if (ctx.hasParent()) { + boolean beanNameRef) { + if (ctx.doingConcreteType()) { + return; + } + + if (overridesVisitAttributes(ctx)) { builder.append(extraTabs).append("\t@Override\n"); } else { GenerateJavadoc.visitAttributes(builder, ctx, extraTabs); @@ -467,18 +536,18 @@ protected void appendVisitAttributes(StringBuilder builder, TypedElementName method = ctx.allTypeInfos().get(i); String typeName = method.typeName().declaredName(); List typeArgs = method.typeName().typeArguments().stream() - .map(it -> it.declaredName() + ".class") + .map(it -> normalize(it.declaredName()) + ".class") .collect(Collectors.toList()); String typeArgsStr = String.join(", ", typeArgs); - builder.append(extraTabs).append("\t\tvisitor.visit(\"").append(attrName).append("\", () -> "); + builder.append(extraTabs).append("\t\tvisitor.visit(\"").append(attrName).append("\", () -> this."); if (beanNameRef) { builder.append(attrName).append(", "); } else { builder.append(method.elementName()).append("(), "); } - builder.append("META_PROPS.get(\"").append(attrName).append("\"), userDefinedCtx, "); - builder.append(typeName).append(".class"); + builder.append(TAG_META_PROPS).append(".get(\"").append(attrName).append("\"), userDefinedCtx, "); + builder.append(normalize(typeName)).append(".class"); if (!typeArgsStr.isBlank()) { builder.append(", ").append(typeArgsStr); } @@ -490,18 +559,26 @@ protected void appendVisitAttributes(StringBuilder builder, builder.append(extraTabs).append("\t}\n\n"); } + /** + * Return true if the visitAttributes() methods is being overridden. + * + * @param ctx the context + * @return true if overriding visitAttributes(); + */ + protected boolean overridesVisitAttributes(BodyContext ctx) { + return ctx.hasParent(); + } + /** * Adds extra default ctor code. * * @param builder the builder - * @param hasParent true if there is a parent for the generated type + * @param ctx the context * @param builderTag the tag (variable name) used for the builder arg - * @param typeInfo the type info */ protected void appendExtraCtorCode(StringBuilder builder, - boolean hasParent, - String builderTag, - TypeInfo typeInfo) { + BodyContext ctx, + String builderTag) { } /** @@ -524,8 +601,8 @@ protected void appendExtraFields(StringBuilder builder, BodyContext ctx) { if (!ctx.doingConcreteType() && ctx.includeMetaAttributes()) { GenerateJavadoc.internalMetaPropsField(builder); - builder.append("\tprotected static final Map> META_PROPS = " - + "Collections.unmodifiableMap(__calcMeta());\n"); + builder.append("\tprotected static final Map> ") + .append(TAG_META_PROPS).append(" = Collections.unmodifiableMap(__calcMeta());\n"); } } @@ -533,32 +610,22 @@ protected void appendExtraFields(StringBuilder builder, * Adds extra toBuilder() methods. * * @param builder the builder - * @param decl the declaration template for the toBuilder method * @param ctx the context + * @param decl the declaration template for the toBuilder method */ protected void appendExtraToBuilderBuilderFunctions(StringBuilder builder, - String decl, - BodyContext ctx) { + BodyContext ctx, + String decl) { } /** * Adds extra builder methods. * - * @param builder the builder - * @param builderGeneratedClassName the builder class name (as written in source form) - * @param builderAnnotation the builder annotation - * @param typeInfo the type info - * @param parentTypeName the parent type name - * @param allAttributeNames all the bean attribute names belonging to the builder - * @param allTypeInfos all the methods belonging to the builder + * @param builder the builder + * @param ctx the context */ protected void appendExtraBuilderFields(StringBuilder builder, - String builderGeneratedClassName, - AnnotationAndValue builderAnnotation, - TypeInfo typeInfo, - TypeName parentTypeName, - List allAttributeNames, - List allTypeInfos) { + BodyContext ctx) { } /** @@ -580,34 +647,26 @@ protected void appendBuilderBuildPreSteps(StringBuilder builder, */ protected void appendExtraBuilderMethods(StringBuilder builder, BodyContext ctx) { - if (ctx.doingConcreteType()) { - return; + if (!ctx.doingConcreteType() && ctx.includeMetaAttributes()) { + appendVisitAttributes(builder, ctx, "\t", true); } - if (ctx.includeMetaAttributes()) { - appendVisitAttributes(builder, "\t", true, ctx); - } + builder.append("\t}\n\n"); } /** * Adds extra meta properties to the generated code. * * @param builder the builder + * @param ctx the context * @param tag the tag used to represent the meta props variable on the generated code - * @param typeInfo the type info - * @param map the map of all the methods - * @param allAttributeNames all the bean attribute names belonging to the builder - * @param allTypeInfos all the methods belonging to the builder * @param needsCustomMapOf will be set to true if a custom map.of() function needs to be generated (i.e., if over 9 tuples) */ protected void appendMetaProps(StringBuilder builder, + BodyContext ctx, String tag, - TypeInfo typeInfo, - Map map, - List allAttributeNames, - List allTypeInfos, AtomicBoolean needsCustomMapOf) { - map.forEach((attrName, method) -> + ctx.map().forEach((attrName, method) -> builder.append("\t\t") .append(tag) .append(".put(\"") @@ -635,18 +694,18 @@ protected String normalizeConfiguredOptionKey(String key, * Appends the singular setter methods on the builder. * * @param builder the builder + * @param ctx the context * @param method the method * @param beanAttributeName the bean attribute name * @param isList true if the output involves List type * @param isMap true if the output involves Map type * @param isSet true if the output involves Set type - * @param ctx the context */ protected void maybeAppendSingularSetter(StringBuilder builder, + BodyContext ctx, TypedElementName method, String beanAttributeName, - boolean isList, boolean isMap, boolean isSet, - BodyContext ctx) { + boolean isList, boolean isMap, boolean isSet) { String singularVal = toValue(Singular.class, method, false, false).orElse(null); if (Objects.nonNull(singularVal) && (isList || isMap || isSet)) { char[] methodName = reverseBeanName(singularVal.isBlank() ? maybeSingularFormOf(beanAttributeName) : singularVal); @@ -672,17 +731,16 @@ protected static String maybeSingularFormOf(String beanAttributeName) { * Append the setters for the given bean attribute name. * * @param mainBuilder the builder + * @param ctx the body context * @param beanAttributeName the bean attribute name * @param methodName the method name * @param method the method - * @param ctx the body context */ protected void appendSetter(StringBuilder mainBuilder, + BodyContext ctx, String beanAttributeName, String methodName, - TypedElementName method, - BodyContext ctx) { - + TypedElementName method) { TypeName typeName = method.typeName(); boolean isList = typeName.isList(); boolean isMap = !isList && typeName.isMap(); @@ -694,11 +752,6 @@ protected void appendSetter(StringBuilder mainBuilder, builder.append("\t\tpublic ").append(ctx.genericBuilderAliasDecl()).append(" ").append(methodName).append("(") .append(toGenerics(method, upLevel)).append(" val) {\n"); - /* - Make sure that arguments are not null - */ - builder.append("\t\t\tObjects.requireNonNull(val);\n"); - /* Assign field, or update collection */ @@ -709,21 +762,21 @@ protected void appendSetter(StringBuilder mainBuilder, builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".addAll(val);\n"); + .append(".addAll(Objects.requireNonNull(val));\n"); } else if (isMap) { builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".putAll(val);\n"); + .append(".putAll(Objects.requireNonNull(val));\n"); } else if (isSet) { builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".addAll(val);\n"); + .append(".addAll(Objects.requireNonNull(val));\n"); } else if (typeName.array()) { builder.append(" = val.clone();\n"); } else { - builder.append(" = val;\n"); + builder.append(" = Objects.requireNonNull(val);\n"); } builder.append("\t\t\treturn identity();\n"); builder.append("\t\t}\n\n"); @@ -963,11 +1016,10 @@ private String toImplTypeSuffix(AnnotationAndValue builderAnnotation) { private void appendBuilder(StringBuilder builder, BodyContext ctx) { appendBuilderHeader(builder, ctx); - appendExtraBuilderFields(builder, ctx.genericBuilderClassDecl(), ctx.builderAnnotation(), - ctx.typeInfo(), ctx.parentTypeName().get(), ctx.allAttributeNames(), ctx.allTypeInfos()); + appendExtraBuilderFields(builder, ctx); appendBuilderBody(builder, ctx); - appendExtraBuilderMethods(builder, ctx); +// appendExtraBuilderMethods(builder, ctx); if (ctx.doingConcreteType()) { if (ctx.hasParent()) { @@ -989,7 +1041,7 @@ private void appendBuilder(StringBuilder builder, boolean isMap = !isList && typeName.isMap(); boolean isSet = !isMap && typeName.isSet(); boolean ignoredUpLevel = isSet || isList; - appendSetter(builder, beanAttributeName, beanAttributeName, method, ctx); + appendSetter(builder, ctx, beanAttributeName, beanAttributeName, method); if (!isList && !isMap && !isSet) { boolean isBoolean = BeanUtils.isBooleanType(typeName.name()); if (isBoolean && beanAttributeName.startsWith("is")) { @@ -998,12 +1050,12 @@ private void appendBuilder(StringBuilder builder, + Character.toLowerCase(beanAttributeName.charAt(2)) + beanAttributeName.substring(3); if (!ctx.allAttributeNames().contains(basicAttributeName)) { - appendSetter(builder, beanAttributeName, basicAttributeName, method, ctx); + appendSetter(builder, ctx, beanAttributeName, basicAttributeName, method); } } } - maybeAppendSingularSetter(builder, method, beanAttributeName, isList, isMap, isSet, ctx); + maybeAppendSingularSetter(builder, ctx, method, beanAttributeName, isList, isMap, isSet); i++; } @@ -1039,7 +1091,11 @@ private void appendBuilder(StringBuilder builder, } } - GenerateJavadoc.accept(builder); + if (ctx.hasParent()) { + builder.append("\t\t@Override\n"); + } else { + GenerateJavadoc.accept(builder); + } builder.append("\t\tpublic ") .append(ctx.genericBuilderAliasDecl()) .append(" accept(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); @@ -1047,11 +1103,11 @@ private void appendBuilder(StringBuilder builder, if (ctx.hasParent()) { builder.append("\t\t\tsuper.accept(val);\n"); } - builder.append("\t\t\tacceptThis(val);\n"); + builder.append("\t\t\t__acceptThis(val);\n"); builder.append("\t\t\treturn identity();\n"); builder.append("\t\t}\n\n"); - builder.append("\t\tprivate void acceptThis(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); + builder.append("\t\tprivate void __acceptThis(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); i = 0; for (String beanAttributeName : ctx.allAttributeNames()) { @@ -1069,14 +1125,12 @@ private void appendBuilder(StringBuilder builder, } builder.append("val.").append(getterName).append("());\n"); } - builder.append("\t\t}\n"); + builder.append("\t\t}\n\n"); } - - // end of the generated builder inner class here - builder.append("\t}\n"); } - private void appendBuilderBody(StringBuilder builder, BodyContext ctx) { + private void appendBuilderBody(StringBuilder builder, + BodyContext ctx) { if (!ctx.doingConcreteType()) { // prepare builder fields, starting with final (list, map, set) boolean hasFinal = false; @@ -1197,9 +1251,20 @@ private void appendBuilderHeader(StringBuilder builder, builder.append("<").append(ctx.genericBuilderAliasDecl()) .append(", ").append(ctx.genericBuilderAcceptAliasDecl()); builder.append(">"); - } else if (ctx.hasStreamSupportOnBuilder()) { + } else { + Optional baseExtendsTypeName = baseExtendsBuilderTypeName(ctx); + if (baseExtendsTypeName.isPresent()) { + builder.append("\n\t\t\t\t\t\t\t\t\t\t" + + "extends ") + .append(baseExtendsTypeName.get().fqName()) + .append("\n\t\t\t\t\t\t\t\t\t\t"); + } + } + + if (ctx.hasStreamSupportOnBuilder()) { builder.append("implements Supplier<").append(ctx.genericBuilderAcceptAliasDecl()).append(">"); } + if (!ctx.hasParent()) { if (ctx.requireLibraryDependencies()) { builder.append(", io.helidon.common.Builder<").append(ctx.genericBuilderAliasDecl()) @@ -1210,6 +1275,9 @@ private void appendBuilderHeader(StringBuilder builder, } } + List extraImplementBuilderContracts = extraImplementedBuilderContracts(ctx); + extraImplementBuilderContracts.forEach(t -> builder.append(",\n\t\t\t\t\t\t\t\t\t\t\t").append(t.fqName())); + builder.append(" {\n"); } } @@ -1220,10 +1288,8 @@ private void appendToBuilderMethods(StringBuilder builder, return; } - GenerateMethod.builderMethods(builder, ctx); - - String decl = "public static Builder toBuilder({args}) {"; - appendExtraToBuilderBuilderFunctions(builder, decl, ctx); + String decl = GenerateMethod.builderMethods(builder, ctx); + appendExtraToBuilderBuilderFunctions(builder, ctx, decl); } private void appendInterfaceBasedGetters(StringBuilder builder, @@ -1247,7 +1313,6 @@ private void appendInterfaceBasedGetters(StringBuilder builder, private void appendCtor(StringBuilder builder, BodyContext ctx) { - GenerateJavadoc.typeConstructorWithBuilder(builder); builder.append("\tprotected ").append(ctx.implTypeName().className()); builder.append("("); @@ -1260,13 +1325,47 @@ private void appendCtor(StringBuilder builder, builder.append(""); } builder.append(" b) {\n"); - appendExtraCtorCode(builder, ctx.hasParent(), "b", ctx.typeInfo()); - appendCtorCode(builder, "b", ctx); + appendExtraCtorCode(builder, ctx, "b"); + appendCtorCodeBody(builder, ctx, "b"); +// builder.append("\t}\n"); } builder.append("\t}\n\n"); } + /** + * Appends the constructor body. + * + * @param builder the builder + * @param ctx the context + * @param builderTag the builder tag + */ + protected void appendCtorCodeBody(StringBuilder builder, + BodyContext ctx, + String builderTag) { + if (ctx.hasParent()) { + builder.append("\t\tsuper(b);\n"); + } + int i = 0; + for (String beanAttributeName : ctx.allAttributeNames()) { + TypedElementName method = ctx.allTypeInfos().get(i++); + builder.append("\t\tthis.").append(beanAttributeName).append(" = "); + + if (method.typeName().isList()) { + builder.append("Collections.unmodifiableList(new ") + .append(ctx.listType()).append("<>(b.").append(beanAttributeName).append("));\n"); + } else if (method.typeName().isMap()) { + builder.append("Collections.unmodifiableMap(new ") + .append(ctx.mapType()).append("<>(b.").append(beanAttributeName).append("));\n"); + } else if (method.typeName().isSet()) { + builder.append("Collections.unmodifiableSet(new ") + .append(ctx.setType()).append("<>(b.").append(beanAttributeName).append("));\n"); + } else { + builder.append("b.").append(beanAttributeName).append(";\n"); + } + } + } + private void appendHashCodeAndEquals(StringBuilder builder, BodyContext ctx) { if (ctx.doingConcreteType()) { @@ -1408,32 +1507,6 @@ private void appendDefaultValueAssignment(StringBuilder builder, } } - private void appendCtorCode(StringBuilder builder, - String ignoredBuilderTag, - BodyContext ctx) { - if (ctx.hasParent()) { - builder.append("\t\tsuper(b);\n"); - } - int i = 0; - for (String beanAttributeName : ctx.allAttributeNames()) { - TypedElementName method = ctx.allTypeInfos().get(i++); - builder.append("\t\tthis.").append(beanAttributeName).append(" = "); - - if (method.typeName().isList()) { - builder.append("Collections.unmodifiableList(new ") - .append(ctx.listType()).append("<>(b.").append(beanAttributeName).append("));\n"); - } else if (method.typeName().isMap()) { - builder.append("Collections.unmodifiableMap(new ") - .append(ctx.mapType()).append("<>(b.").append(beanAttributeName).append("));\n"); - } else if (method.typeName().isSet()) { - builder.append("Collections.unmodifiableSet(new ") - .append(ctx.setType()).append("<>(b.").append(beanAttributeName).append("));\n"); - } else { - builder.append("b.").append(beanAttributeName).append(";\n"); - } - } - } - private void appendOverridesOfDefaultValues(StringBuilder builder, BodyContext ctx) { boolean first = true; @@ -1503,7 +1576,7 @@ private String mapOf(String attrName, String typeDecl = "\"type\", " + typeName.name() + ".class"; if (!typeName.typeArguments().isEmpty()) { int pos = typeName.typeArguments().size() - 1; - typeDecl += ", \"componentType\", " + typeName.typeArguments().get(pos).name() + ".class"; + typeDecl += ", \"componentType\", " + normalize(typeName.typeArguments().get(pos).name()) + ".class"; } String key = (configuredOptions.isEmpty()) @@ -1542,6 +1615,10 @@ private String mapOf(String attrName, return result.toString(); } + private String normalize(String name) { + return name.equals("?") ? "Object" : name; + } + private String quotedTupleOf(String key, String val) { assert (Objects.nonNull(key)); diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java index 0b7fc795fc9..e8cc9e99d23 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java @@ -48,7 +48,7 @@ static void builderMethod(StringBuilder builder, builder.append("\t/**\n" + "\t * Creates a builder for this type.\n" + "\t *\n"); - builder.append("\t * @return A builder for {@link "); + builder.append("\t * @return a builder for {@link "); builder.append(ctx.typeInfo().typeName()); builder.append("}\n\t */\n"); } @@ -56,10 +56,10 @@ static void builderMethod(StringBuilder builder, static void toBuilderMethod(StringBuilder builder, BodyContext ctx) { builder.append("\t/**\n" - + "\t * Creates a builder for this type, initialized with the attributes from the values passed" - + ".\n\n"); + + "\t * Creates a builder for this type, initialized with the attributes from the values passed.\n" + + "\t *\n"); builder.append("\t * @param val the value to copy to initialize the builder attributes\n"); - builder.append("\t * @return A builder for {@link ").append(ctx.typeInfo().typeName()); + builder.append("\t * @return a builder for {@link ").append(ctx.typeInfo().typeName()); builder.append("}\n\t */\n"); } diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java index 516b5356b31..89c5cd247f8 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java @@ -26,7 +26,7 @@ final class GenerateMethod { private GenerateMethod() { } - static void builderMethods(StringBuilder builder, + static String builderMethods(StringBuilder builder, BodyContext ctx) { GenerateJavadoc.builderMethod(builder, ctx); builder.append("\tpublic static Builder"); @@ -40,6 +40,8 @@ static void builderMethods(StringBuilder builder, builder.append("\t\tObjects.requireNonNull(val);\n"); builder.append("\t\treturn builder().accept(val);\n"); builder.append("\t}\n\n"); + + return "public static Builder toBuilder({args})"; } static void stringToCharSetter(StringBuilder builder, @@ -60,7 +62,7 @@ static void stringToCharSetter(StringBuilder builder, static void internalMetaAttributes(StringBuilder builder) { GenerateJavadoc.internalMetaAttributes(builder); builder.append("\tpublic static Map> __metaAttributes() {\n" - + "\t\treturn META_PROPS;\n" + + "\t\treturn ").append(BodyContext.TAG_META_PROPS).append(";\n" + "\t}\n\n"); } diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitor.java b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java similarity index 97% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitor.java rename to pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java index 9494351394d..80bf74a439f 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitor.java +++ b/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java @@ -16,11 +16,11 @@ package io.helidon.pico.builder.processor.tools; -final class GenerateVisitor { - private GenerateVisitor() { +final class GenerateVisitorSupport { + private GenerateVisitorSupport() { } - static void appendAttributeVisitors(StringBuilder builder, + static void appendExtraInnerClasses(StringBuilder builder, BodyContext ctx) { if (ctx.doingConcreteType()) { return; diff --git a/pico/builder/tests/builder/pom.xml b/pico/builder/tests/builder/pom.xml index 4efc5f7ad57..d19a71fbbbd 100644 --- a/pico/builder/tests/builder/pom.xml +++ b/pico/builder/tests/builder/pom.xml @@ -47,12 +47,11 @@ io.helidon.pico.builder - helidon-pico-builder-processor - provided + helidon-pico-builder - io.helidon.pico.builder - helidon-pico-builder + io.helidon.pico.builder.config + helidon-pico-builder-config io.helidon.config diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java b/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java index fcd49976094..7d0bba9b188 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java +++ b/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java @@ -53,6 +53,13 @@ public interface ComplexCase extends MyConfigBean { */ Set> getSetOfLists(); + /** + * Used for testing. + * + * @return ignored, here for testing purposes only + */ + Class getClassType(); + /** * The Pico Builder will ignore {@code default} and {@code static} functions. * diff --git a/pico/builder/tests/builder/src/main/java/module-info.java b/pico/builder/tests/builder/src/main/java/module-info.java index fe7ebf18b7c..23b72f8123d 100644 --- a/pico/builder/tests/builder/src/main/java/module-info.java +++ b/pico/builder/tests/builder/src/main/java/module-info.java @@ -20,6 +20,7 @@ module io.helidon.pico.builder.test.builder { requires static com.fasterxml.jackson.annotation; requires static io.helidon.config.metadata; - requires io.helidon.pico.builder; + requires io.helidon.common; + requires io.helidon.pico.builder; } diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java b/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java index 1d2470e037f..168e458cfac 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java +++ b/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java @@ -40,10 +40,11 @@ void testIt() { .name("name") .mapOfKeyToConfigBeans(mapWithNull) .setOfLists(Collections.singleton(Collections.singletonList(null))) + .classType(Object.class) .build(); assertThat(val.toString(), equalTo("ComplexCase(name=name, enabled=false, port=8080, mapOfKeyToConfigBeans={key=null}, " - + "listOfConfigBeans=[], setOfLists=[[null]])")); + + "listOfConfigBeans=[], setOfLists=[[null]], classType=class java.lang.Object)")); } } diff --git a/pico/builder/tests/pom.xml b/pico/builder/tests/pom.xml index e1577ee98cd..72894e24189 100644 --- a/pico/builder/tests/pom.xml +++ b/pico/builder/tests/pom.xml @@ -36,6 +36,15 @@ Helidon Pico Builder Tests Project pom + + true + true + + true + true + true + + builder diff --git a/pico/pom.xml b/pico/pom.xml index 681bc471128..2f7242dbbfe 100644 --- a/pico/pom.xml +++ b/pico/pom.xml @@ -47,6 +47,7 @@ types builder + builder-config pico diff --git a/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java b/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java index 8ebaa76e328..e8893d8809f 100644 --- a/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java +++ b/pico/types/src/main/java/io/helidon/pico/types/DefaultTypeName.java @@ -126,7 +126,6 @@ public static DefaultTypeName createFromTypeName(String typeName) { return createFromTypeName(typeName.substring(10).trim()) .toBuilder() .wildcard(true) - .generic(true) .build(); } @@ -158,6 +157,18 @@ public static DefaultTypeName createFromTypeName(String typeName) { return create(packageName, className); } + /** + * Given a typeName X, will return an typeName of "? extends X". + * + * @param typeName the typeName + * @return the wildcard extension of the given typeName + */ + public static TypeName createExtendsTypeName(TypeName typeName) { + return toBuilder(typeName) + .wildcard(true) + .build(); + } + /** * Throws an exception if the provided type name is not fully qualified, having a package and class name representation. * @@ -325,13 +336,7 @@ protected Builder() { * @param val the typeName */ protected Builder(TypeName val) { - this.packageName = val.packageName(); - this.className = val.className(); - this.primitive = val.primitive(); - this.array = val.array(); - this.wildcard = val.wildcard(); - this.generic = val.generic(); - this.typeArguments.addAll(val.typeArguments()); + copyFrom(val); } /** @@ -346,6 +351,23 @@ public DefaultTypeName build() { return new DefaultTypeName(this); } + /** + * Copy from an existing typeName. + * + * @param val the typeName to copy + * @return the fluent builder + */ + protected Builder copyFrom(TypeName val) { + this.packageName = val.packageName(); + this.className = val.className(); + this.primitive = val.primitive(); + this.array = val.array(); + this.wildcard = val.wildcard(); + this.generic = val.generic(); + this.typeArguments.addAll(val.typeArguments()); + return this; + } + /** * Set the package name. * diff --git a/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java b/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java index fa76c112307..9a36366cba7 100644 --- a/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java +++ b/pico/types/src/test/java/io/helidon/pico/types/test/DefaultTypeNameTest.java @@ -300,4 +300,12 @@ void builderOfType() { assertThat(objTypeName.className(), equalTo("Boolean")); } + @Test + void extendsTypeName() { + TypeName extendsName = DefaultTypeName.createExtendsTypeName(create(Map.class)); + assertThat(extendsName.fqName(), equalTo("? extends java.util.Map")); + assertThat(extendsName.declaredName(), equalTo("java.util.Map")); + assertThat(extendsName.name(), equalTo("java.util.Map")); + } + } From 127c6e5c291f7f9b42d6ddf6cf36710e64bcab8c Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Mon, 21 Nov 2022 17:40:23 -0500 Subject: [PATCH 24/36] checkstyle suppression, and javadoc fixups --- etc/checkstyle-suppressions.xml | 11 +- .../config/fakes/config/FakeClientAuth.java | 49 - .../config/FakeComponentTracingConfig.java | 223 ----- .../config/fakes/config/FakeKeyConfig.java | 839 ----------------- .../fakes/config/FakeKeystoreConfig.java | 132 --- .../fakes/config/FakePathTracingConfig.java | 179 ---- .../fakes/config/FakeRoutingConfig.java | 699 -------------- .../config/fakes/config/FakeServerConfig.java | 763 ---------------- .../fakes/config/FakeServerLifecycle.java | 38 - .../config/fakes/config/FakeSocketConfig.java | 849 ------------------ .../config/FakeSpanLogTracingConfig.java | 128 --- .../fakes/config/FakeSpanTracingConfig.java | 258 ------ .../fakes/config/FakeTraceableConfig.java | 56 -- .../config/fakes/config/FakeTracer.java | 103 --- .../fakes/config/FakeTracingConfig.java | 244 ----- .../fakes/config/FakeWebServerTlsConfig.java | 438 --------- .../config/fakes/config/SSLContextConfig.java | 201 ----- .../config/testsubjects/ClientConfig.java | 21 +- .../config/testsubjects/CommonConfig.java | 23 + .../config/testsubjects/ServerConfig.java | 13 + .../package-info.java} | 14 +- .../builder/config/fakes/FakeClientAuth.java | 0 .../fakes/FakeComponentTracingConfig.java | 0 .../builder/config/fakes/FakeKeyConfig.java | 0 .../config/fakes/FakeKeystoreConfig.java | 0 .../config/fakes/FakeNettyClientAuth.java | 0 .../config/fakes/FakePathTracingConfig.java | 0 .../config/fakes/FakeRoutingConfig.java | 0 .../config/fakes/FakeServerConfig.java | 0 .../config/fakes/FakeServerLifecycle.java | 0 .../config/fakes/FakeSocketConfig.java | 0 .../fakes/FakeSpanLogTracingConfig.java | 0 .../config/fakes/FakeSpanTracingConfig.java | 0 .../config/fakes/FakeTraceableConfig.java | 0 .../pico/builder/config/fakes/FakeTracer.java | 0 .../config/fakes/FakeTracingConfig.java | 0 .../builder/config/fakes/FakeWebServer.java | 0 .../config/fakes/FakeWebServerTlsConfig.java | 0 .../config/fakes/SSLContextConfig.java | 0 .../pico/builder/config/fakes/WebServer.java | 0 40 files changed, 69 insertions(+), 5212 deletions(-) delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java delete mode 100644 pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java rename pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/{fakes/config/FakeNettyClientAuth.java => testsubjects/package-info.java} (78%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeTracer.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java (100%) rename pico/builder-config/tests/configbean/src/{main => test}/java/io/helidon/pico/builder/config/fakes/WebServer.java (100%) diff --git a/etc/checkstyle-suppressions.xml b/etc/checkstyle-suppressions.xml index 4897aff7cb5..ffc6a4e56ea 100644 --- a/etc/checkstyle-suppressions.xml +++ b/etc/checkstyle-suppressions.xml @@ -77,5 +77,14 @@ - + + + + + + diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java deleted file mode 100644 index 1f6fb1a11a7..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeClientAuth.java +++ /dev/null @@ -1,49 +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.pico.builder.config.fakes.config; - -/** - * Indicates whether the server requires authentication of tbe client by the certificate. - */ -public enum FakeClientAuth { - - /** - * Authentication is required. - */ - REQUIRE(FakeNettyClientAuth.REQUIRE), - - /** - * Authentication is optional. - */ - OPTIONAL(FakeNettyClientAuth.OPTIONAL), - - /** - * Authentication is not required. - */ - NONE(FakeNettyClientAuth.NONE); - - private final FakeNettyClientAuth clientAuth; - - FakeClientAuth(FakeNettyClientAuth clientAuth) { - this.clientAuth = clientAuth; - } - - FakeNettyClientAuth nettyClientAuth(){ - return clientAuth; - } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java deleted file mode 100644 index 182690407bc..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeComponentTracingConfig.java +++ /dev/null @@ -1,223 +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.pico.builder.config.fakes.config; - -import java.util.Map; - -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka ComponentTracing. - */ -@ConfigBean -public interface FakeComponentTracingConfig extends FakeTraceableConfig { -// /** -// * Disabled component - all subsequent calls return disabled spans and logs. -// */ -// public static final ComponentTracingConfig DISABLED = ComponentTracingConfig.builder("disabled").enabled(false).build(); -// /** -// * Enabled component - all subsequent calls return enabled spans and logs. -// */ -// public static final ComponentTracingConfig ENABLED = ComponentTracingConfig.builder("enabled").build(); - -// /** -// * A new named component. -// * -// * @param name name of the component -// */ -// protected ComponentTracingConfig(String name) { -// super(name); -// } -// - -// /** -// * Merge configuration of two traced components. This enabled hierarchical configuration -// * with common, default configuration in one traced component and override in another. -// * -// * @param older the older configuration with "defaults" -// * @param newer the newer configuration to override defaults in older -// * @return merged component -// */ -// static ComponentTracingConfig merge(ComponentTracingConfig older, ComponentTracingConfig newer) { -// return new ComponentTracingConfig(newer.name()) { -// @Override -// public Optional getSpan(String spanName) { -// if (!enabled()) { -// return Optional.of(SpanTracingConfig.DISABLED); -// } -// -// Optional newSpan = newer.getSpan(spanName); -// Optional oldSpan = older.getSpan(spanName); -// -// // both configured -// if (newSpan.isPresent() && oldSpan.isPresent()) { -// return Optional.of(SpanTracingConfig.merge(oldSpan.get(), newSpan.get())); -// } -// -// // only newer -// if (newSpan.isPresent()) { -// return newSpan; -// } -// -// return oldSpan; -// } -// -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// }; -// } -// -// /** -// * Get a traced span configuration for a named span. -// * -// * @param spanName name of the span in this component -// * @return configuration of that span if present -// */ -// protected abstract Optional getSpan(String spanName); -// -// /** -// * Get a traced span configuration for a named span. -// * -// * @param spanName name of a span in this component -// * @return configuration of the span, or enabled configuration if not configured -// * @see #span(String, boolean) -// */ -// public SpanTracingConfig span(String spanName) { -// return span(spanName, true); -// } - - @Singular("span") // Builder::addSpan(String span, FakeSpanLogTracingConfigBean val), Impl::getSpan(String span), etc. - Map spanLogMap(); - -// -// /** -// * Get a traced span configuration for a named span. -// * -// * @param spanName name of a span in this component -// * @param enabledByDefault whether the result is enabled if a configuration is not present -// * @return configuration of the span, or a span configuration enabled or disabled depending on {@code enabledByDefault} if -// * not configured -// */ -// public SpanTracingConfig span(String spanName, boolean enabledByDefault) { -// if (enabled()) { -// return getSpan(spanName).orElseGet(() -> enabledByDefault ? SpanTracingConfig.ENABLED : SpanTracingConfig.DISABLED); -// } -// -// return SpanTracingConfig.DISABLED; -// } -// -// /** -// * Fluent API builder for traced component. -// * -// * @param name the name of the component -// * @return a new builder instance -// */ -// public static Builder builder(String name) { -// return new Builder(name); -// } -// -// /** -// * Create a new traced component configuration from {@link Config}. -// * -// * @param name name of the component -// * @param config config for a new component -// * @return a new traced component configuration -// */ -// public static ComponentTracingConfig create(String name, Config config) { -// return builder(name) -// .config(config) -// .build(); -// } -// -// /** -// * Fluent API builder for {@link ComponentTracingConfig}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final Map tracedSpans = new HashMap<>(); -// private Optional enabled = Optional.empty(); -// private final String name; -// -// private Builder(String name) { -// this.name = name; -// } -// -// @Override -// public ComponentTracingConfig build() { -// // immutability -// final Optional finalEnabled = enabled; -// final Map finalSpans = new HashMap<>(tracedSpans); -// return new ComponentTracingConfig(name) { -// @Override -// public Optional getSpan(String spanName) { -// if (enabled.orElse(true)) { -// return Optional.ofNullable(finalSpans.get(spanName)); -// } else { -// return Optional.of(SpanTracingConfig.DISABLED); -// } -// } -// -// @Override -// public Optional isEnabled() { -// return finalEnabled; -// } -// }; -// } -// -// /** -// * Update this builder from {@link io.helidon.config.Config}. -// * -// * @param config configuration of a traced component -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// config.get("spans").asNodeList().ifPresent(spanConfigList -> { -// spanConfigList.forEach(spanConfig -> { -// // span name is mandatory -// addSpan(SpanTracingConfig.create(spanConfig.get("name").asString().get(), spanConfig)); -// }); -// }); -// return this; -// } -// -// /** -// * Add a new traced span configuration. -// * -// * @param span configuration of a traced span -// * @return updated builder instance -// */ -// public Builder addSpan(SpanTracingConfig span) { -// this.tracedSpans.put(span.name(), span); -// return this; -// } -// -// /** -// * Configure whether this component is enabled or disabled. -// * -// * @param enabled if disabled, all spans and logs will be disabled -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java deleted file mode 100644 index 3adb14006fc..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeyConfig.java +++ /dev/null @@ -1,839 +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.pico.builder.config.fakes.config; - -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.Optional; - -import io.helidon.pico.builder.Builder; - -/** - * aka KeyConfig. - * - */ -@Builder -public interface FakeKeyConfig { - - // /*private static final*/ String DEFAULT_PRIVATE_KEY_ALIAS = "1"; -// /*private static final*/ char[] EMPTY_CHARS = new char[0]; - -// private static final Logger LOGGER = Logger.getLogger(FakeKeyConfigBean.class.getName()); -// -// private final PrivateKey privateKey; -// private final PublicKey publicKey; -// private final X509Certificate publicCert; -// private final List certChain = new LinkedList<>(); -// private final List certificates = new LinkedList<>(); -// -// private FakeKeyConfigBean(PrivateKey privateKey, -// PublicKey publicKey, -// X509Certificate publicCert, -// Collection certChain, -// Collection certificates) { -// -// this.privateKey = privateKey; -// this.publicKey = publicKey; -// this.publicCert = publicCert; -// this.certChain.addAll(certChain); -// this.certificates.addAll(certificates); -// } -// -// /** -// * Load key config from config. -// * -// * @param config config instance located at keys configuration (expects "keystore-path" child) -// * @return KeyConfig loaded from config -// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured -// */ -// public static FakeKeyConfigBean create(Config config) throws PkiException { -// try { -// return fullBuilder().config(config).build(); -// } catch (ResourceException e) { -// throw new PkiException("Failed to load from config", e); -// } -// } -// -// /** -// * Creates a new builder to configure instance. -// * -// * @return builder instance -// */ -// public static Builder fullBuilder() { -// return new Builder(); -// } -// -// /** -// * Build this instance from PEM files (usually a pair of private key and certificate chain). -// * Call {@link PemBuilder#build()} to build the instance. -// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. -// * -// * @return builder for PEM files -// */ -// public static PemBuilder pemBuilder() { -// return new PemBuilder(); -// } -// -// /** -// * Build this instance from a java keystore (such as PKCS12 keystore). -// * Call {@link KeystoreBuilder#build()} to build the instance. -// * If you need to add additional information to {@link FakeKeyConfigBean}, use {@link PemBuilder#toFullBuilder()}. -// * -// * @return builder for Keystore -// */ -// public static KeystoreBuilder keystoreBuilder() { -// return new KeystoreBuilder(); -// } -// - /** - * The public key of this config if configured. - * - * @return the public key of this config or empty if not configured - */ - /*public*/ Optional publicKey(); -// { -// return Optional.ofNullable(publicKey); -// } - - /** - * The private key of this config if configured. - * - * @return the private key of this config or empty if not configured - */ - /*public*/ Optional privateKey(); -// { -// return Optional.ofNullable(privateKey); -// } - - /** - * The public X.509 Certificate if configured. - * - * @return the public certificate of this config or empty if not configured - */ - /*public*/ Optional publicCert(); -// { -// return Optional.ofNullable(publicCert); -// } - - /** - * The X.509 Certificate Chain. - * - * @return the certificate chain or empty list if not configured - */ - /*public*/ List certChain(); -// { -// return Collections.unmodifiableList(certChain); -// } - - /** - * The X.509 Certificates. - * - * @return the certificates configured or empty list if none configured - */ - /*public*/ List certs(); -// { -// return Collections.unmodifiableList(certificates); -// } - - -// public DefaultFakeConfigBean.Builder config(Config config) { -// Config keystoreConfig = config.get("keystore"); -// -// // the actual resource (file, classpath) with the bytes of the keystore -// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); -// -// // type of keystore -// keystoreConfig.get("type") -// .asString() -// .ifPresent(this::keystoreType); -// // password of the keystore -// keystoreConfig.get("passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keystorePassphrase); -// // private key alias -// keystoreConfig.get("key.alias") -// .asString() -// .ifPresent(this::keyAlias); -// // private key password -// keystoreConfig.get("key.passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keyPassphrase); -// keystoreConfig.get("cert.alias") -// .asString() -// .ifPresent(this::certAlias); -// keystoreConfig.get("cert-chain.alias") -// .asString() -// .ifPresent(this::certChainAlias); -// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) -// keystoreConfig.get("trust-store") -// .asBoolean() -// .ifPresent(this::trustStore); -// -// return this; -// } - - -// /** -// * Fluent API builder for {@link FakeKeyConfigBean}. -// * Call {@link #build()} to create an instance. -// * -// * The keys may be loaded from multiple possible sources. -// * -// * @see FakeKeyConfigBean#keystoreBuilder() -// * @see FakeKeyConfigBean#pemBuilder() -// * @see FakeKeyConfigBean#fullBuilder() -// */ -// @Configured -// public static class Builder implements io.helidon.common.Builder { -// private PrivateKey explicitPrivateKey; -// private PublicKey explicitPublicKey; -// private X509Certificate explicitPublicCert; -// private final List explicitCertChain = new LinkedList<>(); -// private final List explicitCertificates = new LinkedList<>(); -// -// /** -// * Build a new instance of the configuration based on this builder. -// * -// * @return instance from this builder -// * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured -// */ -// @Override -// public FakeKeyConfigBean build() throws PkiException { -// PrivateKey privateKey = this.explicitPrivateKey; -// PublicKey publicKey = this.explicitPublicKey; -// X509Certificate publicCert = this.explicitPublicCert; -// List certChain = new LinkedList<>(explicitCertChain); -// List certificates = new LinkedList<>(explicitCertificates); -// -// // fix public key if cert is provided -// if (null == publicKey && null != publicCert) { -// publicKey = publicCert.getPublicKey(); -// } -// -// return new FakeKeyConfigBean(privateKey, publicKey, publicCert, certChain, certificates); -// } -// -// /** -// * Configure a private key instance (rather then keystore and alias). -// * -// * @param privateKey private key instance -// * @return updated builder instance -// */ -// public Builder privateKey(PrivateKey privateKey) { -// this.explicitPrivateKey = privateKey; -// return this; -// } -// -// /** -// * Configure a public key instance (rather then keystore and certificate alias). -// * -// * @param publicKey private key instance -// * @return updated builder instance -// */ -// public Builder publicKey(PublicKey publicKey) { -// this.explicitPublicKey = publicKey; -// return this; -// } -// -// /** -// * Configure an X.509 certificate instance for public key certificate. -// * -// * @param certificate certificate instance -// * @return updated builder instance -// */ -// public Builder publicKeyCert(X509Certificate certificate) { -// this.explicitPublicCert = certificate; -// return this; -// } -// -// /** -// * Add an X.509 certificate instance to the end of certification chain. -// * -// * @param certificate certificate to add to certification path -// * @return updated builder instance -// */ -// public Builder addCertChain(X509Certificate certificate) { -// this.explicitCertChain.add(certificate); -// return this; -// } -// -// /** -// * Add a certificate to the list of certificates, used e.g. in a trust store. -// * -// * @param certificate X.509 certificate to trust -// * @return updated builder instance -// */ -// public Builder addCert(X509Certificate certificate) { -// this.explicitCertificates.add(certificate); -// return this; -// } -// -// /** -// * Update this builder with information from a pem builder. -// * -// * @param builder builder obtained from {@link FakeKeyConfigBean#pemBuilder()} -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "pem") -// public Builder updateWith(PemBuilder builder) { -// builder.updateBuilder(this); -// return this; -// } -// -// /** -// * Update this builder with information from a keystore builder. -// * -// * @param builder builder obtained from {@link FakeKeyConfigBean#keystoreBuilder()} ()} -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "keystore") -// public Builder updateWith(KeystoreBuilder builder) { -// builder.updateBuilder(this); -// return this; -// } -// -// /** -// * Updated this builder instance from configuration. -// * Keys configured will override existing fields in this builder, others will be left intact. -// * If certification path is already defined, configuration based cert-path will be added. -// * -// * @param config configuration to update this builder from -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// updateWith(pemBuilder().config(config)); -// updateWith(keystoreBuilder().config(config)); -// -// return this; -// } -// } -// -// /** -// * Builder for resources from a java keystore (PKCS12, JKS etc.). Obtain an instance through {@link -// * FakeKeyConfigBean#keystoreBuilder()}. -// */ -// @Configured(ignoreBuildMethod = true) -// public static final class KeystoreBuilder implements io.helidon.common.Builder { -// private static final String DEFAULT_KEYSTORE_TYPE = "PKCS12"; -// -// private String keystoreType = DEFAULT_KEYSTORE_TYPE; -// private char[] keystorePassphrase = EMPTY_CHARS; -// private char[] keyPassphrase = null; -// private String keyAlias; -// private String certAlias; -// private String certChainAlias; -// private boolean addAllCertificates; -// private final List certificateAliases = new LinkedList<>(); -// private final StreamHolder keystoreStream = new StreamHolder("keystore"); -// -// private KeystoreBuilder() { -// } -// -// /** -// * If you want to build a trust store, call this method to add all -// * certificates present in the keystore to certificate list. -// * -// * @return updated builder instance -// */ -// @ConfiguredOption(type = Boolean.class, value = "false") -// public KeystoreBuilder trustStore() { -// return trustStore(true); -// } -// -// private KeystoreBuilder trustStore(boolean isTrustStore) { -// this.addAllCertificates = isTrustStore; -// return this; -// } -// -// /** -// * Add an alias to list of aliases used to generate a trusted set of certificates. -// * -// * @param alias alias of a certificate -// * @return updated builder instance -// */ -// public KeystoreBuilder addCertAlias(String alias) { -// certificateAliases.add(alias); -// return this; -// } -// -// /** -// * Keystore resource definition. -// * -// * @param keystore keystore resource, from file path, classpath, URL etc. -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "resource", required = true) -// public KeystoreBuilder keystore(Resource keystore) { -// this.keystoreStream.stream(keystore); -// return this; -// } -// -// /** -// * Set type of keystore. -// * Defaults to "PKCS12", expected are other keystore types supported by java then can store keys under aliases. -// * -// * @param keystoreType keystore type to load the key -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "type", value = "PKCS12") -// public KeystoreBuilder keystoreType(String keystoreType) { -// this.keystoreType = keystoreType; -// return this; -// } -// -// /** -// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). -// * -// * @param keystorePassphrase keystore pass-phrase -// * @return updated builder instance -// */ -// public KeystoreBuilder keystorePassphrase(char[] keystorePassphrase) { -// this.keystorePassphrase = Arrays.copyOf(keystorePassphrase, keystorePassphrase.length); -// -// return this; -// } -// -// /** -// * Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). -// * -// * @param keystorePassword keystore password to use, calls {@link #keystorePassphrase(char[])} -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "passphrase") -// public KeystoreBuilder keystorePassphrase(String keystorePassword) { -// return keystorePassphrase(keystorePassword.toCharArray()); -// } -// -// /** -// * Alias of the private key in the keystore. -// * -// * @param keyAlias alias of the key in the keystore -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.alias", value = "1") -// public KeystoreBuilder keyAlias(String keyAlias) { -// this.keyAlias = keyAlias; -// return this; -// } -// -// /** -// * Alias of X.509 certificate of public key. -// * Used to load both the certificate and public key. -// * -// * @param alias alias under which the certificate is stored in the keystore -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "cert.alias") -// public KeystoreBuilder certAlias(String alias) { -// this.certAlias = alias; -// return this; -// } -// -// /** -// * Alias of an X.509 chain. -// * -// * @param alias alias of certificate chain in the keystore -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "cert-chain.alias") -// public KeystoreBuilder certChainAlias(String alias) { -// this.certChainAlias = alias; -// return this; -// } -// -// /** -// * 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. -// * -// * @param privateKeyPassphrase pass-phrase of the key -// * @return updated builder instance -// */ -// public KeystoreBuilder keyPassphrase(char[] privateKeyPassphrase) { -// this.keyPassphrase = Arrays.copyOf(privateKeyPassphrase, privateKeyPassphrase.length); -// -// return this; -// } -// -// /** -// * 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. -// * -// * @param privateKeyPassphrase pass-phrase of the key -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.passphrase") -// public KeystoreBuilder keyPassphrase(String privateKeyPassphrase) { -// return keyPassphrase(privateKeyPassphrase.toCharArray()); -// } -// -// /** -// * Create an instance of {@link FakeKeyConfigBean} based on this builder. -// * -// * @return new key config based on a keystore -// */ -// @Override -// public FakeKeyConfigBean build() { -// return toFullBuilder().build(); -// } -// -// /** -// * Create a builder for {@link FakeKeyConfigBean} from this keystore builder. This allows you to enhance the config -// * with additional (explicit) fields. -// * -// * @return builder of {@link FakeKeyConfigBean} -// */ -// public Builder toFullBuilder() { -// return updateBuilder(FakeKeyConfigBean.fullBuilder()); -// } -// - -// private Builder updateBuilder(Builder builder) { -// if (keystoreStream.isSet()) { -// if (null == keyPassphrase) { -// keyPassphrase = keystorePassphrase; -// } -// KeyStore keyStore; -// -// try { -// keyStore = PkiUtil.loadKeystore(keystoreType, -// keystoreStream.stream(), -// keystorePassphrase, -// keystoreStream.message()); -// } finally { -// keystoreStream.closeStream(); -// } -// -// // attempt to read private key -// boolean guessing = false; -// if (null == keyAlias) { -// keyAlias = DEFAULT_PRIVATE_KEY_ALIAS; -// guessing = true; -// } -// try { -// builder.privateKey(PkiUtil.loadPrivateKey(keyStore, keyAlias, keyPassphrase)); -// } catch (Exception e) { -// if (guessing) { -// LOGGER.log(Level.FINEST, "Failed to read private key from default alias", e); -// } else { -// throw e; -// } -// } -// -// List certChain = null; -// if (null == certChainAlias) { -// guessing = true; -// // by default, cert chain uses the same alias as private key -// certChainAlias = keyAlias; -// } else { -// guessing = false; -// } -// -// if (null != certChainAlias) { -// try { -// certChain = PkiUtil.loadCertChain(keyStore, certChainAlias); -// certChain.forEach(builder::addCertChain); -// } catch (Exception e) { -// if (guessing) { -// LOGGER.log(Level.FINEST, "Failed to certificate chain from alias \"" + certChainAlias + "\"", e); -// } else { -// throw e; -// } -// } -// } -// -// if (null == certAlias) { -// // no explicit public key certificate, just load it from cert chain if present -// if (null != certChain && !certChain.isEmpty()) { -// builder.publicKeyCert(certChain.get(0)); -// } -// } else { -// builder.publicKeyCert(PkiUtil.loadCertificate(keyStore, certAlias)); -// } -// -// if (addAllCertificates) { -// PkiUtil.loadCertificates(keyStore).forEach(builder::addCert); -// } else { -// certificateAliases.forEach(it -> builder.addCert(PkiUtil.loadCertificate(keyStore, it))); -// } -// } -// return builder; -// } -// -// /** -// * Update this builder from configuration. -// * The following keys are expected under key {@code keystore}: -// *

    -// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • -// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • -// *
  • {@code passphrase}: passphrase of keystore, if required
  • -// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • -// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • -// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • -// *
  • {@code cert-chain.alias}: alias of certificate chain
  • -// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • -// *
-// * -// * @param config configuration instance -// * @return updated builder instance -// */ -// public KeystoreBuilder config(Config config) { -// Config keystoreConfig = config.get("keystore"); -// -// // the actual resource (file, classpath) with the bytes of the keystore -// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); -// -// // type of keystore -// keystoreConfig.get("type") -// .asString() -// .ifPresent(this::keystoreType); -// // password of the keystore -// keystoreConfig.get("passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keystorePassphrase); -// // private key alias -// keystoreConfig.get("key.alias") -// .asString() -// .ifPresent(this::keyAlias); -// // private key password -// keystoreConfig.get("key.passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keyPassphrase); -// keystoreConfig.get("cert.alias") -// .asString() -// .ifPresent(this::certAlias); -// keystoreConfig.get("cert-chain.alias") -// .asString() -// .ifPresent(this::certChainAlias); -// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) -// keystoreConfig.get("trust-store") -// .asBoolean() -// .ifPresent(this::trustStore); -// -// return this; -// } -// } -// - -// /** -// * Builder for PEM files - accepts private key and certificate chain. Obtain an instance through {@link -// * FakeKeyConfigBean#pemBuilder()}. -// * -// * If you have "standard" linux/unix private key, you must run " -// * {@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa.p8}" on it to work with this builder for password protected -// * file; or "{@code openssl pkcs8 -topk8 -in ./id_rsa -out ./id_rsa_nocrypt.p8 -nocrypt}" for unprotected file. -// * -// * The only supported format is PKCS#8. If you have a different format, you must to transform it to PKCS8 PEM format (to -// * use this builder), or to PKCS#12 keystore format (and use {@link KeystoreBuilder}). -// */ -// @Configured(ignoreBuildMethod = true) -// public static final class PemBuilder implements io.helidon.common.Builder { -// private final StreamHolder privateKeyStream = new StreamHolder("privateKey"); -// private final StreamHolder publicKeyStream = new StreamHolder("publicKey"); -// private final StreamHolder certChainStream = new StreamHolder("certChain"); -// private final StreamHolder certificateStream = new StreamHolder("certificate"); -// private char[] pemKeyPassphrase; -// -// private PemBuilder() { -// } -// -// /** -// * Read a private key from PEM format from a resource definition. -// * -// * @param resource key resource (file, classpath, URL etc.) -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.resource") -// public PemBuilder key(Resource resource) { -// privateKeyStream.stream(resource); -// return this; -// } -// -// /** -// * Read a public key from PEM format from a resource definition. -// * -// * @param resource key resource (file, classpath, URL etc.) -// * @return updated builder instance -// */ -// public PemBuilder publicKey(Resource resource) { -// publicKeyStream.stream(resource); -// return this; -// } -// -// /** -// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to -// * decrypt it. -// * -// * @param passphrase passphrase used to encrypt the private key -// * @return updated builder instance -// */ -// public PemBuilder keyPassphrase(char[] passphrase) { -// this.pemKeyPassphrase = Arrays.copyOf(passphrase, passphrase.length); -// -// return this; -// } -// -// /** -// * Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to -// * decrypt it. -// * -// * @param passphrase passphrase used to encrypt the private key -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "key.passphrase") -// public PemBuilder keyPassphrase(String passphrase) { -// return keyPassphrase(passphrase.toCharArray()); -// } -// -// /** -// * Load certificate chain from PEM resource. -// * -// * @param resource resource (e.g. classpath, file path, URL etc.) -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "cert-chain.resource") -// public PemBuilder certChain(Resource resource) { -// certChainStream.stream(resource); -// return this; -// } -// -// /** -// * Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. -// * -// * @param resource key resource (file, classpath, URL etc.) -// * @return updated builder instance -// */ -// public PemBuilder certificates(Resource resource) { -// certificateStream.stream(resource); -// return this; -// } -// -// /** -// * Build {@link FakeKeyConfigBean} based on information from PEM files only. -// * -// * @return new instance configured from this builder -// */ -// @Override -// public FakeKeyConfigBean build() { -// return toFullBuilder().build(); -// } -// -// /** -// * Get a builder filled from this builder to add additional information (such as public key from certificate etc.). -// * -// * @return builder for {@link FakeKeyConfigBean} -// */ -// public Builder toFullBuilder() { -// return updateBuilder(FakeKeyConfigBean.fullBuilder()); -// } -// -// private Builder updateBuilder(Builder builder) { -// if (privateKeyStream.isSet()) { -// builder.privateKey(PemReader.readPrivateKey(privateKeyStream.stream(), pemKeyPassphrase)); -// } -// if (publicKeyStream.isSet()) { -// builder.publicKey(PemReader.readPublicKey(publicKeyStream.stream())); -// } -// -// if (certChainStream.isSet()) { -// List chain = PemReader.readCertificates(certChainStream.stream()); -// chain.forEach(builder::addCertChain); -// if (!chain.isEmpty()) { -// builder.publicKeyCert(chain.get(0)); -// } -// } -// -// if (certificateStream.isSet()) { -// PemReader.readCertificates(certificateStream.stream()).forEach(builder::addCert); -// } -// -// return builder; -// } -// -// /** -// * Update this builder from configuration. -// * Expected keys: -// *
    -// *
  • pem-key-path - path to PEM private key file (PKCS#8 format)
  • -// *
  • pem-key-resource-path - path to resource on classpath
  • -// *
  • pem-key-passphrase - passphrase of private key if encrypted
  • -// *
  • pem-cert-chain-path - path to certificate chain PEM file
  • -// *
  • pem-cert-chain-resource-path - path to resource on classpath
  • -// *
-// * -// * @param config configuration to update builder from -// * @return updated builder instance -// */ -// public PemBuilder config(Config config) { -// Config pemConfig = config.get("pem"); -// pemConfig.get("key.resource").as(Resource::create).ifPresent(this::key); -// pemConfig.get("key.passphrase").asString().map(String::toCharArray).ifPresent(this::keyPassphrase); -// pemConfig.get("cert-chain.resource").as(Resource::create).ifPresent(this::certChain); -// pemConfig.get("certificates.resource").as(Resource::create).ifPresent(this::certificates); -// return this; -// } -// } -// -// private static final class StreamHolder { -// private final String baseMessage; -// private InputStream inputStream; -// private String message; -// -// private StreamHolder(String message) { -// this.baseMessage = message; -// this.message = message; -// } -// -// private boolean isSet() { -// return inputStream != null; -// } -// -// private void stream(Resource resource) { -// closeStream(); -// Objects.requireNonNull(resource, "Resource for \"" + message + "\" must not be null"); -// -// this.inputStream = resource.stream(); -// this.message = message + ":" + resource.sourceType() + ":" + resource.location(); -// } -// -// private InputStream stream() { -// return inputStream; -// } -// -// private String message() { -// return message; -// } -// -// private void closeStream() { -// if (null != inputStream) { -// try { -// inputStream.close(); -// } catch (IOException e) { -// LOGGER.log(Level.WARNING, "Failed to close input stream: " + message, e); -// } -// } -// message = baseMessage; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java deleted file mode 100644 index 563db6276a3..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeKeystoreConfig.java +++ /dev/null @@ -1,132 +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.pico.builder.config.fakes.config; - -import java.util.List; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka KeyConfig.Keystore.Builder - */ -@ConfigBean -public interface FakeKeystoreConfig { - - String DEFAULT_KEYSTORE_TYPE = "PKCS12"; - -// private final StreamHolder keystoreStream = new StreamHolder("keystore"); - -// default FakeKeystoreConfigBean trustStore() { -// return trustStore(true); -// } - - @ConfiguredOption(key = "trust-store") - boolean trustStore(); - -// /** -// * Keystore resource definition. -// * -// * @param keystore keystore resource, from file path, classpath, URL etc. -// * @return updated builder instance -// */ -// @ConfiguredOption(key = "resource", required = true) -// public KeystoreBuilder keystore(Resource keystore) { -// this.keystoreStream.stream(keystore); -// return this; -// } -// default DefaultFakeKeystoreConfigBean.Builder keystore(Resource keystore) { -// -// } - - @ConfiguredOption(key = "type", value = DEFAULT_KEYSTORE_TYPE) - String keystoreType(); - - @ConfiguredOption(key = "passphrase") - char[] keystorePassphrase(); - - @ConfiguredOption(key = "key.alias", value = "1") - String keyAlias(); - - @ConfiguredOption(key = "key.passphrase") - char[] keyPassphrase(); - - @ConfiguredOption(key = "cert.alias") - @Singular("certAlias") - List certAliases(); - - @ConfiguredOption(key = "cert-chain.alias") - String certChainAlias(); - - -// /** -// * Update this builder from configuration. -// * The following keys are expected under key {@code keystore}: -// *
    -// *
  • {@code resource}: resource configuration as understood by {@link io.helidon.common.configurable.Resource}
  • -// *
  • {@code type}: type of keystore (defaults to PKCS12)
  • -// *
  • {@code passphrase}: passphrase of keystore, if required
  • -// *
  • {@code key.alias}: alias of private key, if wanted (defaults to "1")
  • -// *
  • {@code key.passphrase}: passphrase of private key if differs from keystore passphrase
  • -// *
  • {@code cert.alias}: alias of public certificate (to obtain public key)
  • -// *
  • {@code cert-chain.alias}: alias of certificate chain
  • -// *
  • {@code trust-store}: true if this is a trust store (and we should load all certificates from it), defaults to false
  • -// *
-// * -// * @param config configuration instance -// * @return updated builder instance -// */ -// public KeystoreBuilder config(Config config) { -// Config keystoreConfig = config.get("keystore"); -// -// // the actual resource (file, classpath) with the bytes of the keystore -// keystoreConfig.get("resource").as(Resource::create).ifPresent(this::keystore); -// -// // type of keystore -// keystoreConfig.get("type") -// .asString() -// .ifPresent(this::keystoreType); -// // password of the keystore -// keystoreConfig.get("passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keystorePassphrase); -// // private key alias -// keystoreConfig.get("key.alias") -// .asString() -// .ifPresent(this::keyAlias); -// // private key password -// keystoreConfig.get("key.passphrase") -// .asString() -// .map(String::toCharArray) -// .ifPresent(this::keyPassphrase); -// keystoreConfig.get("cert.alias") -// .asString() -// .ifPresent(this::certAlias); -// keystoreConfig.get("cert-chain.alias") -// .asString() -// .ifPresent(this::certChainAlias); -// // whether this is a keystore (with a private key) or a trust store (just trusted public keys/certificates) -// keystoreConfig.get("trust-store") -// .asBoolean() -// .ifPresent(this::trustStore); -// -// return this; -// } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java deleted file mode 100644 index 6a8f321ae6d..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakePathTracingConfig.java +++ /dev/null @@ -1,179 +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.pico.builder.config.fakes.config; - -import java.util.List; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka PathTracing. - * - * Traced system configuration for web server for a specific path. - */ -@ConfigBean -public interface FakePathTracingConfig { -// /** -// * Create a new traced path configuration from {@link io.helidon.config.Config}. -// * @param config config of a path -// * @return traced path configuration -// */ -// static FakePathTracingConfigBean create(Config config) { -// return builder().config(config).build(); -// } -// -// /** -// * Create a new builder to configure traced path configuration. -// * -// * @return a new builder instance -// */ -// static Builder builder() { -// return new Builder(); -// } - - /** - * Path this configuration should configure. - * - * @return path on the web server - */ - String path(); - - /** - * Method(s) this configuration should be valid for. This can be used to restrict the configuration - * only to specific HTTP methods (such as {@code GET} or {@code POST}). - * - * @return list of methods, if empty, this configuration is valid for any method - */ - @Singular("method") // Builder::addMethod(String method); - List methods(); - -// /** -// * Associated configuration of tracing valid for the configured path and (possibly) methods. -// * -// * @return traced system configuration -// */ - @ConfiguredOption(required = true) - FakeTracingConfig tracedConfig(); - -// Optional tracedConfig(); - - -// /** -// * Fluent API builder for {@link FakePathTracingConfigBean}. -// */ -// final class Builder implements io.helidon.common.Builder { -// private final List methods = new LinkedList<>(); -// private String path; -// private TracingConfig tracedConfig; -// -// private Builder() { -// } -// -// @Override -// public FakePathTracingConfigBean build() { -// // immutable -// final String finalPath = path; -// final List finalMethods = new LinkedList<>(methods); -// final TracingConfig finalTracingConfig = tracedConfig; -// -// return new FakePathTracingConfigBean() { -// @Override -// public String path() { -// return finalPath; -// } -// -// @Override -// public List methods() { -// return finalMethods; -// } -// -// @Override -// public TracingConfig tracedConfig() { -// return finalTracingConfig; -// } -// -// @Override -// public String toString() { -// return path + "(" + finalMethods + "): " + finalTracingConfig; -// } -// }; -// } -// -// /** -// * Update this builder from provided {@link io.helidon.config.Config}. -// * -// * @param config config to update this builder from -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// path(config.get("path").asString().get()); -// List methods = config.get("methods").asList(String.class).orElse(null); -// if (null != methods) { -// methods(methods); -// } -// tracingConfig(TracingConfig.create(config)); -// -// return this; -// } -// -// /** -// * Path to register the traced configuration on. -// * -// * @param path path as understood by {@link io.helidon.webserver.Routing.Builder} of web server -// * @return updated builder instance -// */ -// public Builder path(String path) { -// this.path = path; -// return this; -// } -// -// /** -// * HTTP methods to restrict registration of this configuration on web server. -// * @param methods list of methods to use, empty means all methods -// * @return updated builder instance -// */ -// public Builder methods(List methods) { -// this.methods.clear(); -// this.methods.addAll(methods); -// return this; -// } -// -// /** -// * Add a new HTTP method to restrict this configuration for. -// * -// * @param method method to add to the list of supported methods -// * @return updated builder instance -// */ -// public Builder addMethod(String method) { -// this.methods.add(method); -// return this; -// } -// -// /** -// * Configuration of a traced system to use on this path and possibly method(s). -// * -// * @param tracedConfig configuration of components, spans and span logs -// * @return updated builder instance -// */ -// public Builder tracingConfig(TracingConfig tracedConfig) { -// this.tracedConfig = tracedConfig; -// return this; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java deleted file mode 100644 index 502b41fdec1..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeRoutingConfig.java +++ /dev/null @@ -1,699 +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.pico.builder.config.fakes.config; - -/* - * 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. - */ - -/** - * aka Routing. - * - * an annotation to get something discovered (i.e., @CustomConfigBean?) - * - * Routing represents composition of HTTP request-response handlers with routing rules. - * It is a cornerstone of the {@link io.helidon.pico.config.fake.helidon.WebServer}. - */ -public interface FakeRoutingConfig extends FakeServerLifecycle { - -// void route(BareRequest bareRequest, BareResponse bareResponse); -// -// /** -// * Creates new instance of {@link Builder routing builder}. -// * -// * @return a new instance -// */ -// static Builder builder() { -// return new Builder(); -// } -// -// /** -// * An API to define HTTP request routing rules. -// * -// * @see Builder -// */ -// interface Rules { -// /** -// * Configuration of tracing for this routing. -// * The configuration may control whether to log specific components, -// * spans and span logs, either globally, or for a specific path and method combinations. -// * -// * @param webTracingConfig WebServer tracing configuration -// * @return Updated routing configuration -// */ -// Rules register(WebTracingConfig webTracingConfig); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param services services to register -// * @return Updated routing configuration -// */ -// Rules register(Service... services); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param serviceBuilders service builder to register; they will be built as a first step of this -// * method execution -// * @return Updated routing configuration -// */ -// @SuppressWarnings("unchecked") -// Rules register(Supplier... serviceBuilders); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param services services to register -// * @return Updated routing configuration -// */ -// Rules register(String pathPattern, Service... services); -// -// /** -// * Registers builder consumer. It enables to separate complex routing definitions to dedicated classes. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param serviceBuilders service builder to register; they will be built as a first step of this -// * method execution -// * @return an updated routing configuration -// */ -// @SuppressWarnings("unchecked") -// Rules register(String pathPattern, Supplier... serviceBuilders); -// -// /** -// * Routes all GET requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules get(Handler... requestHandlers); -// -// /** -// * Routes GET requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules get(String pathPattern, Handler... requestHandlers); -// -// /** -// * Add a route. This allows also protocol version specific routing. -// * -// * @param route route to add -// * @return updated rules -// */ -// Rules route(HttpRoute route); -// -// /** -// * Routes GET requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules get(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all PUT requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules put(Handler... requestHandlers); -// -// /** -// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules put(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes PUT requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for a registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules put(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all POST requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules post(Handler... requestHandlers); -// -// /** -// * Routes POST requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules post(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes POST requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules post(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all RFC 5789 PATCH requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules patch(Handler... requestHandlers); -// -// /** -// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules patch(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes RFC 5789 PATCH requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules patch(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all DELETE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules delete(Handler... requestHandlers); -// -// /** -// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules delete(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes DELETE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules delete(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all OPTIONS requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules options(Handler... requestHandlers); -// -// /** -// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules options(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes OPTIONS requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules options(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all HEAD requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules head(Handler... requestHandlers); -// -// /** -// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules head(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes HEAD requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules head(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all TRACE requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules trace(Handler... requestHandlers); -// -// /** -// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules trace(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes TRACE requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules trace(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes all requests to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules any(Handler... requestHandlers); -// -// /** -// * Routes all requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules any(String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes all requests with corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules any(PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Routes requests any specified method to provided handler(s). Request handler can call {@link ServerRequest#next()} -// * to continue processing on the next registered handler. -// * -// * @param methods HTTP methods -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules anyOf(Iterable methods, Handler... requestHandlers); -// -// /** -// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param methods HTTP methods -// * @param pathPattern a URI path pattern. See {@link PathMatcher} for pattern syntax reference. -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules anyOf(Iterable methods, String pathPattern, Handler... requestHandlers); -// -// /** -// * Routes requests with any specified method and corresponding path to provided handler(s). Request handler can call -// * {@link ServerRequest#next()} to continue processing on the next registered handler. -// * -// * @param methods HTTP methods -// * @param pathMatcher define path for registered router -// * @param requestHandlers handlers to process HTTP request -// * @return an updated routing configuration -// */ -// Rules anyOf(Iterable methods, PathMatcher pathMatcher, Handler... requestHandlers); -// -// /** -// * Registers callback on created new {@link WebServer} instance with this routing. -// * -// * @param webServerConsumer a WebServer creation callback -// * @return updated routing configuration -// */ -// Rules onNewWebServer(Consumer webServerConsumer); -// } -// -// /** -// * A {@link Routing} builder. -// */ -// class Builder implements Rules, io.helidon.common.Builder { -// -// private final RouteListRoutingRules delegate = new RouteListRoutingRules(); -// private final List> errorHandlerRecords = new ArrayList<>(); -// private boolean tracingRegistered; -// -// /** -// * Creates new instance. -// */ -// private Builder() { -// } -// -// // --------------- ROUTING API -// -// @Override -// public Builder register(WebTracingConfig webTracingConfig) { -// this.tracingRegistered = true; -// delegate.register(webTracingConfig); -// return this; -// } -// -// @Override -// @SuppressWarnings("unchecked") -// public Builder register(Supplier... serviceBuilders) { -// delegate.register(serviceBuilders); -// return this; -// } -// -// @Override -// public Builder register(Service... services) { -// delegate.register(services); -// return this; -// } -// -// @Override -// public Builder register(String pathPattern, Service... services) { -// delegate.register(pathPattern, services); -// return this; -// } -// -// @Override -// @SuppressWarnings("unchecked") -// public Builder register(String pathPattern, Supplier... serviceBuilders) { -// delegate.register(pathPattern, serviceBuilders); -// return this; -// } -// -// @Override -// public Builder get(Handler... requestHandlers) { -// delegate.get(requestHandlers); -// return this; -// } -// -// @Override -// public Builder get(String pathPattern, Handler... requestHandlers) { -// delegate.get(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder route(HttpRoute route) { -// delegate.register(route); -// return this; -// } -// -// @Override -// public Builder get(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.get(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder put(Handler... requestHandlers) { -// delegate.put(requestHandlers); -// return this; -// } -// -// @Override -// public Builder put(String pathPattern, Handler... requestHandlers) { -// delegate.put(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder put(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.put(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder post(Handler... requestHandlers) { -// delegate.post(requestHandlers); -// return this; -// } -// -// @Override -// public Builder post(String pathPattern, Handler... requestHandlers) { -// delegate.post(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder post(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.post(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder patch(Handler... requestHandlers) { -// delegate.patch(requestHandlers); -// return this; -// } -// -// @Override -// public Builder patch(String pathPattern, Handler... requestHandlers) { -// delegate.patch(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder patch(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.patch(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder delete(Handler... requestHandlers) { -// delegate.delete(requestHandlers); -// return this; -// } -// -// @Override -// public Builder delete(String pathPattern, Handler... requestHandlers) { -// delegate.delete(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder delete(PathMatcher pathMatcher, -// Handler... requestHandlers) { -// delegate.delete(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder options(Handler... requestHandlers) { -// delegate.options(requestHandlers); -// return this; -// } -// -// @Override -// public Builder options(String pathPattern, Handler... requestHandlers) { -// delegate.options(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder options(PathMatcher pathMatcher, -// Handler... requestHandlers) { -// delegate.options(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder head(Handler... requestHandlers) { -// delegate.head(requestHandlers); -// return this; -// } -// -// @Override -// public Builder head(String pathPattern, Handler... requestHandlers) { -// delegate.head(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder head(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.head(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder trace(Handler... requestHandlers) { -// delegate.trace(requestHandlers); -// return this; -// } -// -// @Override -// public Builder trace(String pathPattern, Handler... requestHandlers) { -// delegate.trace(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder trace(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.trace(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder any(Handler... requestHandlers) { -// delegate.any(requestHandlers); -// return this; -// } -// -// @Override -// public Builder any(String pathPattern, Handler... requestHandlers) { -// delegate.any(pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder any(PathMatcher pathMatcher, Handler... requestHandlers) { -// delegate.any(pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder anyOf(Iterable methods, Handler... requestHandlers) { -// delegate.anyOf(methods, requestHandlers); -// return this; -// } -// -// @Override -// public Builder anyOf(Iterable methods, String pathPattern, Handler... requestHandlers) { -// delegate.anyOf(methods, pathPattern, requestHandlers); -// return this; -// } -// -// @Override -// public Builder anyOf(Iterable methods, -// PathMatcher pathMatcher, -// Handler... requestHandlers) { -// delegate.anyOf(methods, pathMatcher, requestHandlers); -// return this; -// } -// -// @Override -// public Builder onNewWebServer(Consumer webServerConsumer) { -// delegate.onNewWebServer(webServerConsumer); -// return this; -// } -// // --------------- ERROR API -// -// /** -// * Registers an error handler that handles the given type of exceptions. -// * -// * @param exceptionClass the type of exception to handle by this handler -// * @param errorHandler the error handler -// * @param an error handler type -// * @return an updated builder -// */ -// public Builder error(Class exceptionClass, ErrorHandler errorHandler) { -// if (errorHandler == null) { -// return this; -// } -// errorHandlerRecords.add(RequestRouting.ErrorHandlerRecord.of(exceptionClass, errorHandler)); -// -// return this; -// } -// -// // --------------- BUILD API -// -// /** -// * Builds a new routing instance. -// * -// * @return a new instance -// */ -// public Routing build() { -// if (!tracingRegistered) { -// register(WebTracingConfig.create()); -// } -// RouteListRoutingRules.Aggregation aggregate = delegate.aggregate(); -// return new RequestRouting(aggregate.routeList(), errorHandlerRecords, aggregate.newWebServerCallbacks()); -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java deleted file mode 100644 index e5b1f3f4a61..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerConfig.java +++ /dev/null @@ -1,763 +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.pico.builder.config.fakes.config; - -import java.time.Duration; -import java.util.Map; -import java.util.Optional; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka ServerConfiguration. - */ -@ConfigBean -public interface FakeServerConfig extends FakeSocketConfig { - - /** - * Returns the count of threads in the pool used to process HTTP requests. - *

- * Default value is {@link Runtime#availableProcessors()}. - * - * @return a workers count - */ - int workersCount(); - - /** - * Returns a server port to listen on with the default server socket. If port is - * {@code 0} then any available ephemeral port will be used. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return the server port of the default server socket - */ - @Override - int port(); - -// /** -// * Returns local address where the server listens on with the default server socket. -// * If {@code null} then listens an all local addresses. -// *

-// * Additional named server socket configuration is accessible through -// * the {@link #socket(String)} and {@link #sockets()} methods. -// * -// * @return an address to bind with the default server socket; {@code null} for all local addresses -// */ -// @Override -// InetAddress bindAddress(); - - /** - * Returns a maximum length of the queue of incoming connections on the default server - * socket. - *

- * Default value is {@link FakeSocketConfig#DEFAULT_BACKLOG_SIZE}. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return a maximum length of the queue of incoming connections - */ - @Override - int backlog(); - - /** - * Returns a default server socket timeout in milliseconds or {@code 0} for an infinite timeout. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return a default server socket timeout in milliseconds or {@code 0} - */ - @Override - int timeoutMillis(); - - /** - * Returns proposed value of the TCP receive window that is advertised to the remote peer on the - * default server socket. - *

- * If {@code 0} then use implementation default. - *

- * Additional named server socket configuration is accessible through - * the {@link #socket(String)} and {@link #sockets()} methods. - * - * @return a buffer size in bytes of the default server socket or {@code 0} - */ - @Override - int receiveBufferSize(); - - /** - * A socket configuration of an additional named server socket. - *

- * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured - * - * @param name the name of the additional server socket - * @return an additional named server socket configuration or {@code null} if there is no such - * named server socket - * @deprecated since 2.0.0, please use {@link #namedSocket(String)} instead - */ - @Deprecated - default FakeSocketConfig socket(String name) { - return namedSocket(name).orElse(null); - } - - /** - * A socket configuration of an additional named server socket. - *

- * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured - * - * @param name the name of the additional server socket - * @return an additional named server socket configuration or {@code empty} if there is no such - * named server socket configured - */ - default Optional namedSocket(String name) { - return Optional.ofNullable(sockets().get(name)); - } - - /** - * A map of all the configured server sockets; that is the default server socket - * which is identified by the key {@link io.helidon.pico.config.fake.helidon.WebServer#DEFAULT_SOCKET_NAME} and also all the additional - * named server socket configurations. - *

- * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured - * - * @return a map of all the configured server sockets, never null - */ - @Singular("socket") - Map sockets(); - - /** - * The maximum amount of time that the server will wait to shut - * down regardless of the value of any additionally requested - * quiet period. - * - *

The default implementation of this method returns {@link - * java.time.Duration#ofSeconds(long) Duration.ofSeconds(10L)}.

- * - * @return the {@link java.time.Duration} to use - */ -// TODO: @DefaultValue (Duration translation) - @ConfiguredOption(key = "whatever") - default Duration maxShutdownTimeout() { - return Duration.ofSeconds(10L); - } - - /** - * The quiet period during which the webserver will wait for new - * incoming connections after it has been told to shut down. - * - *

The webserver will wait no longer than the duration returned - * by the {@link #maxShutdownTimeout()} method.

- * - *

The default implementation of this method returns {@link - * java.time.Duration#ofSeconds(long) Duration.ofSeconds(0L)}, indicating - * that there will be no quiet period.

- * - * @return the {@link java.time.Duration} to use - */ - default Duration shutdownQuietPeriod() { - return Duration.ofSeconds(0L); - } - -// /** -// * Returns a Tracer. -// * -// * @return a tracer to use - never {@code null} -// */ -// Tracer tracer(); - -// /** -// * The top level {@link io.helidon.common.context.Context} to be used by this webserver. -// * @return a context instance with registered application scoped instances -// */ -// Context context(); -// -// /** -// * Returns an optional {@link Transport}. -// * -// * @return an optional {@link Transport} -// */ -// default Optional transport() { -// return Optional.ofNullable(null); -// } - - /** - * Whether to print details of HelidonFeatures. - * - * @return whether to print details - */ - boolean printFeatureDetails(); - -// /** -// * Creates new instance with defaults from external configuration source. -// * -// * @param config the externalized configuration -// * @return a new instance -// */ -// static FakeServerConfigBean create(Config config) { -// return builder(config).build(); -// } -// -// /** -// * Creates new instance of a {@link Builder server configuration builder}. -// * -// * @return a new builder instance -// * -// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()} instead -// */ -// @Deprecated -// static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Creates new instance of a {@link Builder server configuration builder} with defaults from external configuration source. -// * -// * @param config the externalized configuration -// * @return a new builder instance -// * @deprecated since 2.0.0 - please use {@link io.helidon.webserver.WebServer#builder()}, then -// * {@link WebServer.Builder#config(io.helidon.config.Config)}, or -// * {@link io.helidon.webserver.WebServer#create(Routing, io.helidon.config.Config)} -// */ -// @Deprecated -// static Builder builder(Config config) { -// return new Builder().config(config); -// } -// -// /** -// * A {@link FakeServerConfigBean} builder. -// * -// * @deprecated since 2.0.0 - use {@link io.helidon.webserver.WebServer.Builder} instead -// */ -// @Deprecated -// final class Builder implements FakeSocketConfigBean.SocketConfigurationBuilder, -// io.helidon.common.Builder { -// -// private static final AtomicInteger WEBSERVER_COUNTER = new AtomicInteger(1); -// private final Map socketBuilders = new HashMap<>(); -// private final Map socketsConfigs = new HashMap<>(); -// private int workers; -// private Tracer tracer; -// private Duration maxShutdownTimeout; -// private Duration shutdownQuietPeriod; -// private Optional transport; -// private Context context; -// private boolean printFeatureDetails; -// -// private Builder() { -// transport = Optional.ofNullable(null); -// maxShutdownTimeout = Duration.ofSeconds(10L); -// shutdownQuietPeriod = Duration.ofSeconds(0L); -// } -// -// /** -// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. -// * -// * @param sslContext ssl context -// * @return an updated builder -// */ -// public Builder ssl(SSLContext sslContext) { -// defaultSocketBuilder().ssl(sslContext); -// return this; -// } -// -// /** -// * Sets {@link SSLContext} to to use with the server. If not {@code null} then server enforce SSL communication. -// * -// * @param sslContextBuilder ssl context builder; will be built as a first step of this method execution -// * @return an updated builder -// */ -// public Builder ssl(Supplier sslContextBuilder) { -// defaultSocketBuilder().ssl(sslContextBuilder); -// return this; -// } -// -// /** -// * Sets server port. If port is {@code 0} or less then any available ephemeral port will be used. -// *

-// * Configuration key: {@code port} -// * -// * @param port the server port -// * @return an updated builder -// */ -// public Builder port(int port) { -// defaultSocketBuilder().port(port); -// return this; -// } -// -// /** -// * Sets a local address for server to bind. If {@code null} then listens an all local addresses. -// *

-// * Configuration key: {@code bind-address} -// * -// * @param bindAddress the address to bind the server or {@code null} for all local addresses -// * @return an updated builder -// */ -// public Builder bindAddress(InetAddress bindAddress) { -// defaultSocketBuilder().bindAddress(bindAddress); -// return this; -// } -// -// /** -// * Sets a maximum length of the queue of incoming connections. Default value is {@code 1024}. -// *

-// * Configuration key: {@code backlog} -// * -// * @param size the maximum length of the queue of incoming connections -// * @return an updated builder -// */ -// public Builder backlog(int size) { -// defaultSocketBuilder().backlog(size); -// return this; -// } -// -// /** -// * Sets a socket timeout in milliseconds or {@code 0} for infinite timeout. -// *

-// * Configuration key: {@code timeout} -// * -// * @param milliseconds a socket timeout in milliseconds or {@code 0} -// * @return an updated builder -// */ -// public Builder timeout(int milliseconds) { -// defaultSocketBuilder().timeoutMillis(milliseconds); -// return this; -// } -// -// /** -// * Propose value of the TCP receive window that is advertised to the remote peer. -// * If {@code 0} then implementation default is used. -// *

-// * Configuration key: {@code receive-buffer} -// * -// * @param bytes a buffer size in bytes or {@code 0} -// * @return an updated builder -// */ -// public Builder receiveBufferSize(int bytes) { -// defaultSocketBuilder().receiveBufferSize(bytes); -// return this; -// } -// -// @Override -// public Builder maxHeaderSize(int size) { -// defaultSocketBuilder().maxHeaderSize(size); -// return this; -// } -// -// @Override -// public Builder maxInitialLineLength(int length) { -// defaultSocketBuilder().maxInitialLineLength(length); -// return this; -// } -// -// /** -// * Adds an additional named server socket configuration. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param port the port to bind; if {@code 0} or less, any available ephemeral port will be used -// * @param bindAddress the address to bind; if {@code null}, all local addresses will be bound -// * @return an updated builder -// * -// * @deprecated since 2.0.0, please use {@link #addSocket(String, FakeSocketConfigBean)} instead -// */ -// @Deprecated -// public Builder addSocket(String name, int port, InetAddress bindAddress) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// return addSocket(name, FakeSocketConfigBean.builder() -// .port(port) -// .bindAddress(bindAddress)); -// } -// -// /** -// * Adds an additional named server socket configuration. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param socketConfiguration the additional named server socket configuration -// * @return an updated builder -// */ -// public Builder addSocket(String name, FakeSocketConfigBean socketConfiguration) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// this.socketsConfigs.put(name, socketConfiguration); -// return this; -// } -// -// /** -// * Adds an additional named server socket configuration. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param socketConfiguration the additional named server socket configuration builder -// * @return an updated builder -// */ -// public Builder addSocket(String name, FakeSocketConfigBean.Builder socketConfiguration) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// this.socketBuilders.put(name, socketConfiguration); -// return this; -// } -// -// /** -// * Adds an additional named server socket configuration builder. As a result, the server will listen -// * on multiple ports. -// *

-// * An additional named server socket may have a dedicated {@link Routing} configured -// * through {@link io.helidon.webserver.WebServer.Builder#addNamedRouting(String, Routing)}. -// * -// * @param name the name of the additional server socket configuration -// * @param socketConfigurationBuilder the additional named server socket configuration builder; will be built as -// * a first step of this method execution -// * @return an updated builder -// */ -// public Builder addSocket(String name, Supplier socketConfigurationBuilder) { -// Objects.requireNonNull(name, "Parameter 'name' must not be null!"); -// -// return addSocket(name, socketConfigurationBuilder != null ? socketConfigurationBuilder.get() : null); -// } -// -// /** -// * Sets a count of threads in pool used to process HTTP requests. -// * Default value is {@code CPU_COUNT * 2}. -// *

-// * Configuration key: {@code workers} -// * -// * @param workers a workers count -// * @return an updated builder -// */ -// public Builder workersCount(int workers) { -// this.workers = workers; -// return this; -// } -// -// /** -// * Sets a tracer. -// * -// * @param tracer a tracer to set -// * @return an updated builder -// */ -// public Builder tracer(Tracer tracer) { -// this.tracer = tracer; -// return this; -// } -// -// /** -// * Sets a tracer. -// * -// * @param tracerBuilder a tracer builder to set; will be built as a first step of this method execution -// * @return updated builder -// */ -// public Builder tracer(Supplier tracerBuilder) { -// return tracer(tracerBuilder.get()); -// } -// -// /** -// * Configures the SSL protocols to enable with the default server socket. -// * @param protocols protocols to enable, if {@code null} enables the -// * default protocols -// * @return an updated builder -// */ -// public Builder enabledSSlProtocols(String... protocols) { -// defaultSocketBuilder().enabledSSlProtocols(protocols); -// return this; -// } -// -// /** -// * Configures the SSL protocols to enable with the default server socket. -// * @param protocols protocols to enable, if {@code null} or empty enables -// * the default protocols -// * @return an updated builder -// */ -// public Builder enabledSSlProtocols(List protocols) { -// defaultSocketBuilder().enabledSSlProtocols(protocols); -// return this; -// } -// -// /** -// * Configure maximum client payload size. -// * @param size maximum payload size -// * @return an updated builder -// */ -// @Override -// public Builder maxPayloadSize(long size) { -// defaultSocketBuilder().maxPayloadSize(size); -// return this; -// } -// -// /** -// * Set a maximum length of the content of an upgrade request. -// *

-// * Default is {@code 64*1024} -// * -// * @param size Maximum length of the content of an upgrade request -// * @return this builder -// */ -// @Override -// public Builder maxUpgradeContentLength(int size) { -// defaultSocketBuilder().maxUpgradeContentLength(size); -// return this; -// } -// -// /** -// * Configure the maximum amount of time that the server will wait to shut -// * down regardless of the value of any additionally requested -// * quiet period. -// * @param maxShutdownTimeout the {@link Duration} to use -// * @return an updated builder -// */ -// public Builder maxShutdownTimeout(Duration maxShutdownTimeout) { -// this.maxShutdownTimeout = -// Objects.requireNonNull(maxShutdownTimeout, "Parameter 'maxShutdownTimeout' must not be null!"); -// return this; -// } -// -// /** -// * Configure the quiet period during which the webserver will wait for new -// * incoming connections after it has been told to shut down. -// * @param shutdownQuietPeriod the {@link Duration} to use -// * @return an updated builder -// */ -// public Builder shutdownQuietPeriod(Duration shutdownQuietPeriod) { -// this.shutdownQuietPeriod = -// Objects.requireNonNull(shutdownQuietPeriod, "Parameter 'shutdownQuietPeriod' must not be null!"); -// return this; -// } -// -// /** -// * Configure transport. -// * @param transport a {@link Transport} -// * @return an updated builder -// */ -// public Builder transport(Transport transport) { -// this.transport = Optional.of(transport); -// return this; -// } -// -// /** -// * Set to {@code true} to print detailed feature information on startup. -// * -// * @param print whether to print details or not -// * @return updated builder instance -// * @see io.helidon.common.HelidonFeatures -// */ -// public Builder printFeatureDetails(boolean print) { -// this.printFeatureDetails = print; -// return this; -// } -// -// /** -// * Configure the application scoped context to be used as a parent for webserver request contexts. -// * @param context top level context -// * @return an updated builder -// */ -// public Builder context(Context context) { -// this.context = context; -// -// return this; -// } -// -// private InetAddress string2InetAddress(String address) { -// try { -// return InetAddress.getByName(address); -// } catch (UnknownHostException e) { -// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); -// } -// } -// -// /** -// * Sets configuration values included in provided {@link Config} parameter. -// *

-// * It can be used for configuration externalisation. -// *

-// * All parameters sets before this method call can be seen as defaults and all parameters sets after can be seen -// * as forced. -// * -// * @param config the configuration to use -// * @return an updated builder -// */ -// public Builder config(Config config) { -// if (config == null) { -// return this; -// } -// -// defaultSocketBuilder().config(config); -// -// config.get("host").asString().ifPresent(defaultSocketBuilder()::host); -// -// DeprecatedConfig.get(config, "worker-count", "workers") -// .asInt() -// .ifPresent(this::workersCount); -// -// config.get("features.print-details").asBoolean().ifPresent(this::printFeatureDetails); -// -// // shutdown timeouts -// config.get("max-shutdown-timeout-seconds").asLong().ifPresent(it -> maxShutdownTimeout(Duration.ofSeconds(it))); -// config.get("shutdown-quiet-period-seconds").asLong().ifPresent(it -> shutdownQuietPeriod(Duration.ofSeconds(it))); -// -// // sockets -// Config socketsConfig = config.get("sockets"); -// if (socketsConfig.exists()) { -// List socketConfigs = socketsConfig.asNodeList().orElse(List.of()); -// for (Config socketConfig : socketConfigs) { -// // the whole section checking the socket name can be removed -// // when we remove deprecated methods with socket name on server builder -// String socketName; -// -// String nodeName = socketConfig.name(); -// Optional maybeSocketName = socketConfig.get("name").asString().asOptional(); -// -// socketName = maybeSocketName.orElse(nodeName); -// -// // log warning for deprecated config -// try { -// Integer.parseInt(nodeName); -// if (socketName.equals(nodeName) && maybeSocketName.isEmpty()) { -// throw new ConfigException("Cannot find \"name\" key for socket configuration " + socketConfig.key()); -// } -// } catch (NumberFormatException e) { -// // this is old approach -// Logger.getLogger(SocketConfigurationBuilder.class.getName()) -// .warning("Socket configuration at " + socketConfig.key() + " is deprecated. Please use an array " -// + "with \"name\" key to define the socket name."); -// } -// -// FakeSocketConfigBean.Builder socket = FakeSocketConfigBean.builder() -// .name(socketName) -// .config(socketConfig); -// -// socketBuilders.put(socket.name(), socket); -// } -// } -// -// return this; -// } -// -// /** -// * Builds a new configuration instance. -// * -// * @return a new instance -// */ -// @Override -// public FakeServerConfigBean build() { -// if (null == context) { -// // I do not expect "unlimited" number of webservers -// // in case somebody spins a huge number up, the counter will cycle to negative numbers once -// // Integer.MAX_VALUE is reached. -// context = Context.builder() -// .id("web-" + WEBSERVER_COUNTER.getAndIncrement()) -// .build(); -// } -// -// Optional maybeTracer = context.get(Tracer.class); -// -// if (null == this.tracer) { -// this.tracer = maybeTracer.orElseGet(Tracer::global); -// } -// -// if (maybeTracer.isEmpty()) { -// context.register(this.tracer); -// } -// -// if (workers <= 0) { -// workers = Runtime.getRuntime().availableProcessors(); -// } -// -// return new ServerBasicConfig(this); -// } -// -// FakeSocketConfigBean.Builder defaultSocketBuilder() { -// return socketBuilder(WebServer.DEFAULT_SOCKET_NAME); -// } -// -// FakeSocketConfigBean.Builder socketBuilder(String socketName) { -// return socketBuilders.computeIfAbsent(socketName, k -> FakeSocketConfigBean.builder().name(socketName)); -// } -// -// Map sockets() { -// Set builtSocketConfigsKeys = socketsConfigs.keySet(); -// Map result = -// new HashMap<>(this.socketBuilders.size() + this.socketsConfigs.size()); -// for (Map.Entry e : this.socketBuilders.entrySet()) { -// String key = e.getKey(); -// if (builtSocketConfigsKeys.contains(key)) { -// throw new IllegalStateException("Both mutable and immutable socket configuration provided for named socket " -// + key); -// } -// result.put(key, e.getValue().build()); -// } -// -// result.putAll(this.socketsConfigs); -// return result; -// } -// -// int workers() { -// return workers; -// } -// -// Tracer tracer() { -// return tracer; -// } -// -// Duration maxShutdownTimeout() { -// return maxShutdownTimeout; -// } -// -// Duration shutdownQuietPeriod() { -// return shutdownQuietPeriod; -// } -// -// Optional transport() { -// return transport; -// } -// -// Context context() { -// return context; -// } -// -// boolean printFeatureDetails() { -// return printFeatureDetails; -// } -// -// @Override -// public Builder timeout(long amount, TimeUnit unit) { -// defaultSocketBuilder().timeout(amount, unit); -// return this; -// } -// -// @Override -// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { -// defaultSocketBuilder().tls(webServerTls); -// return this; -// } -// -// @Override -// public Builder enableCompression(boolean value) { -// defaultSocketBuilder().enableCompression(value); -// return this; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java deleted file mode 100644 index 49dd3296f63..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeServerLifecycle.java +++ /dev/null @@ -1,38 +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.pico.builder.config.fakes.config; - -/** - * aka ServerLifecycle. - * - * Basic server lifecycle operations. - */ -public interface FakeServerLifecycle { - -// /** -// * Before server start. -// */ -// default void beforeStart() { -// } -// -// /** -// * After server stop. -// */ -// default void afterStop() { -// } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java deleted file mode 100644 index 6adf615a31b..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSocketConfig.java +++ /dev/null @@ -1,849 +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.pico.builder.config.fakes.config; - -/* - * 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 java.util.Optional; -import java.util.Set; - -import javax.net.ssl.SSLContext; - -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.config.ConfigBean; -import io.helidon.pico.builder.config.fakes.WebServer; - -/** - * aka ServerConfiguration. - * - * The SocketConfiguration configures a port to listen on and its associated server socket parameters. - */ -@ConfigBean -public interface FakeSocketConfig { - - /** - * The default backlog size to configure the server sockets with if no other value - * is provided. - */ - int DEFAULT_BACKLOG_SIZE = 1024; - - /** - * Name of this socket. - * Default to WebServer#DEFAULT_SOCKET_NAME for the main and - * default server socket. All other sockets must be named. - * - * @return name of this socket - */ -// default String name() { -// return WebServer.DEFAULT_SOCKET_NAME; -// } - @ConfiguredOption(WebServer.DEFAULT_SOCKET_NAME) - String name(); - - /** - * Returns a server port to listen on with the server socket. If port is - * {@code 0} then any available ephemeral port will be used. - * - * @return the server port of the server socket - */ - int port(); - -// /** -// * Returns local address where the server listens on with the server socket. -// * If {@code null} then listens an all local addresses. -// * -// * @return an address to bind with the server socket; {@code null} for all local addresses -// */ -// InetAddress bindAddress(); - @ConfiguredOption(key = "bind-address") - String bindAddress(); - - /** - * Returns a maximum length of the queue of incoming connections on the server - * socket. - *

- * Default value is {@link #DEFAULT_BACKLOG_SIZE}. - * - * @return a maximum length of the queue of incoming connections - */ - @ConfiguredOption("1024") - int backlog(); - - /** - * Returns a server socket timeout in milliseconds or {@code 0} for an infinite timeout. - * - * @return a server socket timeout in milliseconds or {@code 0} - */ - @ConfiguredOption(key = "timeout-millis") - int timeoutMillis(); - - /** - * Returns proposed value of the TCP receive window that is advertised to the remote peer on the - * server socket. - *

- * If {@code 0} then use implementation default. - * - * @return a buffer size in bytes of the server socket or {@code 0} - */ - int receiveBufferSize(); - - /** - * Return a {@link FakeWebServerTlsConfig} containing server TLS configuration. When empty {@link java.util.Optional} is returned - * no TLS should be configured. - * - * @return web server tls configuration - */ - Optional tls(); - - /** - * Returns a {@link javax.net.ssl.SSLContext} to use with the server socket. If not {@code null} then - * the server enforces an SSL communication. - * - * @deprecated use {@code tls().sslContext()} instead. This method will be removed at 3.0.0 version. - * @return a SSL context to use - */ - @Deprecated(since = "2.3.1", forRemoval = true) - SSLContext ssl(); - - /** - * Returns the SSL protocols to enable, or {@code null} to enable the default - * protocols. - * @deprecated use {@code tls().enabledTlsProtocols()} instead. This method will be removed at 3.0.0 version. - * @return the SSL protocols to enable - */ - @Deprecated(since = "2.3.1", forRemoval = true) - Set enabledSslProtocols(); - - /** - * Return the allowed cipher suite of the TLS. If empty set is returned, the default cipher suite is used. - * - * @deprecated use {@code tls().cipherSuite()} instead. This method will be removed at 3.0.0 version. - * @return the allowed cipher suite - */ - @Deprecated(since = "2.3.1", forRemoval = true) - Set allowedCipherSuite(); - - /** - * Whether to require client authentication or not. - * - * @deprecated use {@code tls().clientAuth()} instead. This method will be removed at 3.0.0 version. - * @return client authentication - */ - @Deprecated(since = "2.3.1", forRemoval = true) - FakeNettyClientAuth clientAuth(); - - /** - * Whether this socket is enabled (and will be opened on server startup), or disabled - * (and ignored on server startup). - * - * @return {@code true} for enabled socket, {@code false} for socket that should not be opened - */ -// default boolean enabled() { -// return true; -// } - @ConfiguredOption("true") - boolean enabled(); - - /** - * Maximal size of all headers combined. - * - * @return size in bytes - */ - // TODO: should we automatically translate camel-case to dashes? - @ConfiguredOption(key = "max-header-size", value = "8192") - int maxHeaderSize(); - - /** - * Maximal length of the initial HTTP line. - * - * @return length - */ - @ConfiguredOption("4096") - int maxInitialLineLength(); - - /** - * Maximal size of a single chunk of received data. - * - * @return chunk size - */ - int maxChunkSize(); - - /** - * Whether to validate HTTP header names. - * When set to {@code true}, we make sure the header name is a valid string - * - * @return {@code true} if headers should be validated - */ - boolean validateHeaders(); - - /** - * Whether to allow negotiation for a gzip/deflate content encoding. Supporting - * HTTP compression may interfere with application that use streaming and other - * similar features. Thus, it defaults to {@code false}. - * - * @return compression flag - */ -// default boolean enableCompression() { -// return false; -// } - boolean enableCompression(); - - /** - * Maximum size allowed for an HTTP payload in a client request. A negative - * value indicates that there is no maximum set. - * - * @return maximum payload size - */ -// default long maxPayloadSize() { -// return -1L; -// } - @ConfiguredOption("-1") - long maxPayloadSize(); - - /** - * Initial size of the buffer used to parse HTTP line and headers. - * - * @return initial size of the buffer - */ - int initialBufferSize(); - - /** - * Maximum length of the content of an upgrade request. - * - * @return maximum length of the content of an upgrade request - */ -// default int maxUpgradeContentLength() { -// return 64 * 1024; -// } - @ConfiguredOption("65536") - int maxUpgradeContentLength(); - -// /** -// * Creates a builder of {@link FakeSocketConfigBean} class. -// * -// * @return a builder -// */ -// static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Create a default named configuration. -// * -// * @param name name of the socket -// * @return a new socket configuration with defaults -// */ -// static FakeSocketConfigBean create(String name) { -// return builder() -// .name(name) -// .build(); -// } -// -// /** -// * Socket configuration builder API, used by {@link io.helidon.webserver.SocketConfiguration.Builder} -// * to configure additional sockets, and by {@link io.helidon.webserver.WebServer.Builder} to -// * configure the default socket. -// * -// * @param type of the subclass of this class to provide correct fluent API -// */ -// @Configured -// interface SocketConfigurationBuilder> { -// /** -// * Configures a server port to listen on with the server socket. If port is -// * {@code 0} then any available ephemeral port will be used. -// * -// * @param port the server port of the server socket -// * @return this builder -// */ -// @ConfiguredOption("0") -// B port(int port); -// -// /** -// * Configures local address where the server listens on with the server socket. -// * If not configured, then listens an all local addresses. -// * -// * @param address an address to bind with the server socket -// * @return this builder -// * @throws java.lang.NullPointerException in case the bind address is null -// * @throws io.helidon.config.ConfigException in case the address provided is not a valid host address -// */ -// @ConfiguredOption(deprecated = true) -// default B bindAddress(String address) { -// try { -// return bindAddress(InetAddress.getByName(address)); -// } catch (UnknownHostException e) { -// throw new ConfigException("Illegal value of 'bind-address' configuration key. Expecting host or ip address!", e); -// } -// } -// -// /** -// * A helper method that just calls {@link #bindAddress(String)}. -// * -// * @param address host to listen on -// * @return this builder -// */ -// @ConfiguredOption -// default B host(String address) { -// return bindAddress(address); -// } -// -// /** -// * Configures local address where the server listens on with the server socket. -// * If not configured, then listens an all local addresses. -// * -// * @param bindAddress an address to bind with the server socket -// * @return this builder -// * @throws java.lang.NullPointerException in case the bind address is null -// */ -// B bindAddress(InetAddress bindAddress); -// -// /** -// * Configures a maximum length of the queue of incoming connections on the server -// * socket. -// *

-// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. -// * -// * @param backlog a maximum length of the queue of incoming connections -// * @return this builder -// */ -// @ConfiguredOption("1024") -// B backlog(int backlog); -// -// /** -// * Configures a server socket timeout. -// * -// * @param amount an amount of time to configure the timeout, use {@code 0} for infinite timeout -// * @param unit time unit to use with the configured amount -// * @return this builder -// */ -// @ConfiguredOption(key = "timeout-millis", type = Long.class, value = "0", -// description = "Socket timeout in milliseconds") -// B timeout(long amount, TimeUnit unit); -// -// /** -// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the -// * server socket. -// *

-// * If {@code 0} then use implementation default. -// * -// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} -// * @return this builder -// */ -// @ConfiguredOption -// B receiveBufferSize(int receiveBufferSize); -// -// /** -// * Configures SSL for this socket. When configured, the server enforces SSL -// * configuration. -// * If this method is called, any other method except for {@link #tls(java.util.function.Supplier)}¨ -// * and repeated invocation of this method would be ignored. -// *

-// * If this method is called again, the previous configuration would be ignored. -// * -// * @param webServerTls ssl configuration to use with this socket -// * @return this builder -// */ -// @ConfiguredOption -// B tls(FakeWebServerTlsConfigBean webServerTls); -// -// /** -// * Configures SSL for this socket. When configured, the server enforces SSL -// * configuration. -// * -// * @param tlsConfig supplier ssl configuration to use with this socket -// * @return this builder -// */ -// default B tls(Supplier tlsConfig) { -// return tls(tlsConfig.get()); -// } -// -// /** -// * Maximal number of bytes of all header values combined. When a bigger value is received, a -// * {@link io.helidon.common.http.Http.Status#BAD_REQUEST_400} -// * is returned. -// *

-// * Default is {@code 8192} -// * -// * @param size maximal number of bytes of combined header values -// * @return this builder -// */ -// @ConfiguredOption("8192") -// B maxHeaderSize(int size); -// -// /** -// * Maximal number of characters in the initial HTTP line. -// *

-// * Default is {@code 4096} -// * -// * @param length maximal number of characters -// * @return this builder -// */ -// @ConfiguredOption("4096") -// B maxInitialLineLength(int length); -// -// /** -// * Enable negotiation for gzip/deflate content encodings. Clients can -// * request compression using the "Accept-Encoding" header. -// *

-// * Default is {@code false} -// * -// * @param value compression flag -// * @return this builder -// */ -// @ConfiguredOption("false") -// B enableCompression(boolean value); -// -// /** -// * Set a maximum payload size for a client request. Can prevent DoS -// * attacks. -// * -// * @param size maximum payload size -// * @return this builder -// */ -// @ConfiguredOption -// B maxPayloadSize(long size); -// -// /** -// * Set a maximum length of the content of an upgrade request. -// *

-// * Default is {@code 64*1024} -// * -// * @param size Maximum length of the content of an upgrade request -// * @return this builder -// */ -// @ConfiguredOption("65536") -// B maxUpgradeContentLength(int size); -// -// /** -// * Update this socket configuration from a {@link io.helidon.config.Config}. -// * -// * @param config configuration on the node of a socket -// * @return updated builder instance -// */ -// @SuppressWarnings("unchecked") -// default B config(Config config) { -// config.get("port").asInt().ifPresent(this::port); -// config.get("bind-address").asString().ifPresent(this::host); -// config.get("backlog").asInt().ifPresent(this::backlog); -// config.get("max-header-size").asInt().ifPresent(this::maxHeaderSize); -// config.get("max-initial-line-length").asInt().ifPresent(this::maxInitialLineLength); -// config.get("max-payload-size").asInt().ifPresent(this::maxPayloadSize); -// -// DeprecatedConfig.get(config, "timeout-millis", "timeout") -// .asInt() -// .ifPresent(it -> this.timeout(it, TimeUnit.MILLISECONDS)); -// DeprecatedConfig.get(config, "receive-buffer-size", "receive-buffer") -// .asInt() -// .ifPresent(this::receiveBufferSize); -// -// Optional> enabledProtocols = DeprecatedConfig.get(config, "ssl.protocols", "ssl-protocols") -// .asList(String.class) -// .asOptional(); -// -// // tls -// Config sslConfig = DeprecatedConfig.get(config, "tls", "ssl"); -// if (sslConfig.exists()) { -// try { -// FakeWebServerTlsConfigBean.Builder builder = FakeWebServerTlsConfigBean.builder(); -// enabledProtocols.ifPresent(builder::enabledProtocols); -// builder.config(sslConfig); -// -// this.tls(builder.build()); -// } catch (IllegalStateException e) { -// throw new ConfigException("Cannot load SSL configuration.", e); -// } -// } -// -// // compression -// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); -// return (B) this; -// } -// } -// -// /** -// * The {@link io.helidon.webserver.SocketConfiguration} builder class. -// */ -// @Configured -// final class Builder implements SocketConfigurationBuilder, io.helidon.common.Builder { -// /** -// * @deprecated remove once WebServer.Builder.addSocket(name, socket) methods are removed -// */ -// @Deprecated -// static final String UNCONFIGURED_NAME = "io.helidon.webserver.SocketConfiguration.UNCONFIGURED"; -// private final FakeWebServerTlsConfigBean.Builder tlsConfigBuilder = FakeWebServerTlsConfigBean.builder(); -// -// private int port = 0; -// private InetAddress bindAddress = null; -// private int backlog = DEFAULT_BACKLOG_SIZE; -// private int timeoutMillis = 0; -// private int receiveBufferSize = 0; -// private FakeWebServerTlsConfigBean webServerTls; -// // this is for backward compatibility, should be initialized to null once the -// // methods with `name` are removed from server builder (for adding sockets) -// private String name = UNCONFIGURED_NAME; -// private boolean enabled = true; -// // these values are as defined in Netty implementation -// private int maxHeaderSize = 8192; -// private int maxInitialLineLength = 4096; -// private int maxChunkSize = 8192; -// private boolean validateHeaders = true; -// private int initialBufferSize = 128; -// private boolean enableCompression = false; -// private long maxPayloadSize = -1; -// private int maxUpgradeContentLength = 64 * 1024; -// -// private Builder() { -// } -// -// @Override -// public FakeSocketConfigBean build() { -// if (null == webServerTls) { -// webServerTls = tlsConfigBuilder.build(); -// } -// -// if (null == name) { -// throw new ConfigException("Socket name must be configured for each socket"); -// } -// -// return new ServerBasicConfig.SocketConfig(this); -// } -// -// @Override -// public Builder port(int port) { -// this.port = port; -// return this; -// } -// -// @Override -// public Builder bindAddress(InetAddress bindAddress) { -// this.bindAddress = bindAddress; -// return this; -// } -// -// /** -// * Configures a maximum length of the queue of incoming connections on the server -// * socket. -// *

-// * Default value is {@link #DEFAULT_BACKLOG_SIZE}. -// * -// * @param backlog a maximum length of the queue of incoming connections -// * @return this builder -// */ -// public Builder backlog(int backlog) { -// this.backlog = backlog; -// return this; -// } -// -// /** -// * Configures a server socket timeout in milliseconds or {@code 0} for an infinite timeout. -// * -// * @param timeoutMillis a server socket timeout in milliseconds or {@code 0} -// * @return this builder -// * -// * @deprecated since 2.0.0 please use {@link #timeout(long, java.util.concurrent.TimeUnit)} instead -// */ -// @Deprecated -// public Builder timeoutMillis(int timeoutMillis) { -// this.timeoutMillis = timeoutMillis; -// return this; -// } -// -// /** -// * Configures proposed value of the TCP receive window that is advertised to the remote peer on the -// * server socket. -// *

-// * If {@code 0} then use implementation default. -// * -// * @param receiveBufferSize a buffer size in bytes of the server socket or {@code 0} -// * @return this builder -// */ -// @Override -// public Builder receiveBufferSize(int receiveBufferSize) { -// this.receiveBufferSize = receiveBufferSize; -// return this; -// } -// -// /** -// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then -// * the server enforces an SSL communication. -// * -// * @param sslContext a SSL context to use -// * @return this builder -// * -// * @deprecated since 2.0.0, please use {@link #tls(FakeWebServerTlsConfigBean)} instead -// */ -// @Deprecated -// public Builder ssl(SSLContext sslContext) { -// if (null != sslContext) { -// this.tlsConfigBuilder.sslContext(sslContext); -// } -// return this; -// } -// -// /** -// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then -// * the server enforces an SSL communication. -// * -// * @param sslContextBuilder a SSL context builder to use; will be built as a first step of this -// * method execution -// * @return this builder -// * @deprecated since 2.0.0, please use {@link #tls(Supplier)} instead -// */ -// @Deprecated -// public Builder ssl(Supplier sslContextBuilder) { -// return ssl(sslContextBuilder != null ? sslContextBuilder.get() : null); -// } -// -// /** -// * Configures the SSL protocols to enable with the server socket. -// * @param protocols protocols to enable, if {@code null} enables the -// * default protocols -// * @return this builder -// * -// * @deprecated since 2.0.0, please use {@link FakeWebServerTlsConfigBean.Builder#enabledProtocols(String...)} -// * instead -// */ -// @Deprecated -// public Builder enabledSSlProtocols(String... protocols) { -// if (null == protocols) { -// enabledSSlProtocols(List.of()); -// } else { -// enabledSSlProtocols(Arrays.asList(protocols)); -// } -// return this; -// } -// -// /** -// * Configures the SSL protocols to enable with the server socket. -// * @param protocols protocols to enable, if {@code null} or empty enables -// * the default protocols -// * @return this builder -// */ -// @Deprecated -// public Builder enabledSSlProtocols(List protocols) { -// if (null == protocols) { -// this.tlsConfigBuilder.enabledProtocols(List.of()); -// } else { -// this.tlsConfigBuilder.enabledProtocols(protocols); -// } -// return this; -// } -// -// @Override -// public Builder timeout(long amount, TimeUnit unit) { -// long timeout = unit.toMillis(amount); -// if (timeout > Integer.MAX_VALUE) { -// this.timeoutMillis = 0; -// } else { -// this.timeoutMillis = (int) timeout; -// } -// return this; -// } -// -// @Override -// public Builder tls(FakeWebServerTlsConfigBean webServerTls) { -// this.webServerTls = webServerTls; -// return this; -// } -// -// @Override -// public Builder maxHeaderSize(int size) { -// this.maxHeaderSize = size; -// return this; -// } -// -// @Override -// public Builder maxInitialLineLength(int length) { -// this.maxInitialLineLength = length; -// return this; -// } -// -// @Override -// public Builder maxPayloadSize(long size) { -// this.maxPayloadSize = size; -// return this; -// } -// -// @Override -// public Builder maxUpgradeContentLength(int size) { -// this.maxUpgradeContentLength = size; -// return this; -// } -// -// /** -// * Configure a socket name, to bind named routings to. -// * -// * @param name name of the socket -// * @return updated builder instance -// */ -// @ConfiguredOption(required = true) -// public Builder name(String name) { -// this.name = name; -// return this; -// } -// -// /** -// * Set this socket builder to enabled or disabled. -// * -// * @param enabled when set to {@code false}, the socket is not going to be opened by the server -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = enabled; -// return this; -// } -// -// /** -// * Configure maximal size of a chunk to be read from incoming requests. -// * Defaults to {@code 8192}. -// * -// * @param size maximal chunk size -// * @return updated builder instance -// */ -// public Builder maxChunkSize(int size) { -// this.maxChunkSize = size; -// return this; -// } -// -// /** -// * Configure whether to validate header names. -// * Defaults to {@code true} to make sure header names are valid strings. -// * -// * @param validate set to {@code false} to ignore header validation -// * @return updated builder instance -// */ -// public Builder validateHeaders(boolean validate) { -// this.validateHeaders = validate; -// return this; -// } -// -// /** -// * Configure initial size of the buffer used to parse HTTP line and headers. -// * Defaults to {@code 128}. -// * -// * @param size initial buffer size -// * @return updated builder instance -// */ -// public Builder initialBufferSize(int size) { -// this.initialBufferSize = size; -// return this; -// } -// -// /** -// * Configure whether to enable content negotiation for compression. -// * -// * @param value compression flag -// * @return updated builder instance -// */ -// public Builder enableCompression(boolean value) { -// this.enableCompression = value; -// return this; -// } -// -// @Override -// public Builder config(Config config) { -// SocketConfigurationBuilder.super.config(config); -// -// config.get("name").asString().ifPresent(this::name); -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// config.get("max-chunk-size").asInt().ifPresent(this::maxChunkSize); -// config.get("validate-headers").asBoolean().ifPresent(this::validateHeaders); -// config.get("initial-buffer-size").asInt().ifPresent(this::initialBufferSize); -// config.get("enable-compression").asBoolean().ifPresent(this::enableCompression); -// -// return this; -// } -// -// int port() { -// return port; -// } -// -// Optional bindAddress() { -// return Optional.ofNullable(bindAddress); -// } -// -// int backlog() { -// return backlog; -// } -// -// int timeoutMillis() { -// return timeoutMillis; -// } -// -// int receiveBufferSize() { -// return receiveBufferSize; -// } -// -// FakeWebServerTlsConfigBean tlsConfig() { -// return webServerTls; -// } -// -// String name() { -// return name; -// } -// -// boolean enabled() { -// return enabled; -// } -// -// int maxHeaderSize() { -// return maxHeaderSize; -// } -// -// int maxInitialLineLength() { -// return maxInitialLineLength; -// } -// -// int maxChunkSize() { -// return maxChunkSize; -// } -// -// boolean validateHeaders() { -// return validateHeaders; -// } -// -// int initialBufferSize() { -// return initialBufferSize; -// } -// -// boolean enableCompression() { -// return enableCompression; -// } -// -// long maxPayloadSize() { -// return maxPayloadSize; -// } -// -// int maxUpgradeContentLength() { -// return maxUpgradeContentLength; -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java deleted file mode 100644 index 719ffc6b3e9..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanLogTracingConfig.java +++ /dev/null @@ -1,128 +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.pico.builder.config.fakes.config; - -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka SpanLogTracingConfig. - */ -@ConfigBean -public interface FakeSpanLogTracingConfig extends FakeTraceableConfig { -// /** -// * Disabled traced span log. -// */ -// public static final FakeSpanLogTracingConfigBean DISABLED = FakeSpanLogTracingConfigBean.builder("disabled").enabled(false).build(); -// /** -// * Enabled traced span log. -// */ -// public static final FakeSpanLogTracingConfigBean ENABLED = FakeSpanLogTracingConfigBean.builder("enabled").build(); -// -// /** -// * A new span log. -// * @param name name of the span log -// */ -// protected FakeSpanLogTracingConfigBean(String name) { -// super(name); -// } -// - -// /** -// * Merge two traced span log configurations. -// * -// * @param older original configuration with default values -// * @param newer new configuration to override the older -// * @return a new traced span log mergint the older and newer -// */ -// static FakeSpanLogTracingConfigBean merge(FakeSpanLogTracingConfigBean older, FakeSpanLogTracingConfigBean newer) { -// return new FakeSpanLogTracingConfigBean(newer.name()) { -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// }; -// } -// -// /** -// * Fluent API builder to create a new traced span log configuration. -// * -// * @param name name of the span log -// * @return a new builder instance -// */ -// public static Builder builder(String name) { -// return new Builder(name); -// } -// -// /** -// * Create a new traced span log configuration from {@link io.helidon.config.Config}. -// * -// * @param name name of the span log -// * @param config config for a traced span log -// * @return a new traced span log configuration -// */ -// public static FakeSpanLogTracingConfigBean create(String name, Config config) { -// return builder(name).config(config).build(); -// } -// -// /** -// * A fluent API builder for {@link FakeSpanLogTracingConfigBean}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final String name; -// private Optional enabled = Optional.empty(); -// -// private Builder(String name) { -// this.name = name; -// } -// -// @Override -// public FakeSpanLogTracingConfigBean build() { -// final Optional finalEnabled = enabled; -// return new FakeSpanLogTracingConfigBean(name) { -// @Override -// public Optional isEnabled() { -// return finalEnabled; -// } -// }; -// } -// -// /** -// * Configure whether this traced span log is enabled or disabled. -// * -// * @param enabled if disabled, this span and all logs will be disabled -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// -// /** -// * Update this builder from {@link io.helidon.config.Config}. -// * -// * @param config config of a traced span log -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// -// return this; -// } -// } -// -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java deleted file mode 100644 index 39a3e2a8130..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeSpanTracingConfig.java +++ /dev/null @@ -1,258 +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.pico.builder.config.fakes.config; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka SpanTracingConfig. - * - * Configuration of a single traced span. - */ -@ConfigBean -public interface FakeSpanTracingConfig extends FakeTraceableConfig { - -// /** -// * A traced span that is disabled and all logs on it are disabled as well. -// */ -// public static final SpanTracingConfig DISABLED = SpanTracingConfig.builder("disabled").enabled(false).build(); -// /** -// * A traced span that is inabled and all logs on it are enabled as well. -// */ -// public static final SpanTracingConfig ENABLED = SpanTracingConfig.builder("enabled").build(); - -// /** -// * A new traceable span. -// * -// * @param name name of this span -// */ -// protected SpanTracingConfig(String name) { -// super(name); -// } -// -// @Override -// public String toString() { -// return "SpanTracingConfig(" + name() + ")"; -// } -// -// /** -// * Merge configuration of two traced spans. -// * -// * @param older older span with default values -// * @param newer newer span overriding values in older -// * @return a new merged traced span configuration -// */ -// static SpanTracingConfig merge(SpanTracingConfig older, SpanTracingConfig newer) { -// return new SpanTracingConfig(newer.name()) { -// @Override -// public Optional newName() { -// return newer.newName() -// .or(older::newName); -// } -// -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// -// @Override -// public Optional getSpanLog(String name) { -// Optional newLog = newer.getSpanLog(name); -// Optional oldLog = older.getSpanLog(name); -// -// if (newLog.isPresent() && oldLog.isPresent()) { -// return Optional.of(SpanLogTracingConfig.merge(oldLog.get(), newLog.get())); -// } -// -// if (newLog.isPresent()) { -// return newLog; -// } -// -// return oldLog; -// } -// }; -// } - - /** - * When rename is desired, returns the new name. - * - * @return new name for this span or empty when rename is not desired - */ - Optional newName(); - -// /** -// * Configuration of a traced span log. -// * -// * @param name name of the log event -// * @return configuration of the log event, or empty if not explicitly configured (used when merging) -// */ -// protected abstract Optional getSpanLog(String name); - - @Singular("spanLog") // B addSpanLog(String, FakeSpanLogTracingConfigBean); - Map spanLogMap(); - -// /** -// * Configuration of a traceable span log. -// * If this span is disabled, the log is always disabled. -// * -// * @param name name of the log event -// * @return configuration of the log event -// */ -// public final SpanLogTracingConfig spanLog(String name) { -// if (enabled()) { -// return getSpanLog(name).orElse(SpanLogTracingConfig.ENABLED); -// } else { -// return SpanLogTracingConfig.DISABLED; -// } -// } -// -// /** -// * Whether a log event should be logged on the span with a default value. -// * -// * @param logName name of the log event -// * @param defaultValue to use in case the log event is not configured in this span's configuration -// * @return whether to log ({@code true}) the event or not ({@code false}), uses the default value for unconfigured logs -// */ -// public boolean logEnabled(String logName, boolean defaultValue) { -// if (enabled()) { -// return getSpanLog(logName).map(Traceable::enabled).orElse(defaultValue); -// } -// return false; -// } -// -// /** -// * A fluent API builder to create traced span configuration. -// * -// * @param name name of the span -// * @return a new builder instance -// */ -// public static Builder builder(String name) { -// return new Builder(name); -// } -// -// /** -// * Create traced span configuration from a {@link io.helidon.config.Config}. -// * -// * @param name name of the span -// * @param config config to load span configuration from -// * @return a new traced span configuration -// */ -// public static SpanTracingConfig create(String name, Config config) { -// return builder(name).config(config).build(); -// } -// -// /** -// * A fluent API builder for {@link SpanTracingConfig}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final Map spanLogMap = new HashMap<>(); -// private final String name; -// private Optional enabled = Optional.empty(); -// private String newName; -// -// private Builder(String name) { -// this.name = name; -// } -// -// @Override -// public SpanTracingConfig build() { -// final Map finalSpanLogMap = new HashMap<>(spanLogMap); -// final Optional finalNewName = Optional.ofNullable(newName); -// final Optional finalEnabled = enabled; -// -// return new SpanTracingConfig(name) { -// @Override -// public Optional newName() { -// return finalNewName; -// } -// -// @Override -// public Optional isEnabled() { -// return finalEnabled; -// } -// -// @Override -// protected Optional getSpanLog(String name) { -// if (enabled.orElse(true)) { -// return Optional.ofNullable(finalSpanLogMap.get(name)); -// } -// return Optional.of(SpanLogTracingConfig.DISABLED); -// } -// }; -// } -// -// /** -// * Configure whether this traced span is enabled or disabled. -// * -// * @param enabled if disabled, this span and all logs will be disabled -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// -// /** -// * Configure a new name of this span. -// * -// * @param newName new name to use when reporting this span -// * @return updated builder instance -// */ -// public Builder newName(String newName) { -// this.newName = newName; -// return this; -// } -// -// /** -// * Add configuration of a traced span log. -// * -// * @param spanLogTracingConfig configuration of the traced span log -// * @return updated builder instance -// */ -// public Builder addSpanLog(SpanLogTracingConfig spanLogTracingConfig) { -// this.spanLogMap.put(spanLogTracingConfig.name(), spanLogTracingConfig); -// return this; -// } -// -// /** -// * Update this builder from {@link io.helidon.config.Config}. -// * -// * @param config configuration of this span -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// config.get("new-name").asString().ifPresent(this::newName); -// config.get("logs") -// .asNodeList() -// .ifPresent(nodes -> { -// nodes.forEach(node -> { -// // name is mandatory -// addSpanLog(SpanLogTracingConfig.create(node.get("name").asString().get(), node)); -// }); -// }); -// -// return this; -// } -// } -// -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java deleted file mode 100644 index ff675ee14f8..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTraceableConfig.java +++ /dev/null @@ -1,56 +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.pico.builder.config.fakes.config; - -import java.util.Optional; - -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka Traceable. - * - * Tracing configuration that can be enabled or disabled. - */ -@ConfigBean -public interface FakeTraceableConfig { - /** - * Whether this trace should be executed or not. - * - * @return {@code true} if span/component should be traced, - * {@code false} if it should not, - * {@code empty} when this flag is not explicitly configured - */ - /*protected*/ Optional isEnabled(); - - /** - * Name of this traceable unit. - * - * @return name - */ - String name(); - - /** - * Whether this traceable should be executed or not. - * - * @return {@code true} if span/component should be traced, - * {@code false} if it should not - */ - default boolean enabled() { - return isEnabled().orElse(true); - } - -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java deleted file mode 100644 index 2e6c258f71b..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracer.java +++ /dev/null @@ -1,103 +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.pico.builder.config.fakes.config; - -/** - * Tracer abstraction. - * Tracer is the central point that collects tracing spans, and (probably) pushes them to backend. - */ -public interface FakeTracer { -// /** -// * Create a no-op tracer. All spans created from this tracer are not doing anything. -// * -// * @return no-op tracer -// */ -// static Tracer noOp() { -// return NoOpTracer.instance(); -// } -// -// /** -// * Get the currently registered global tracer. -// * -// * @return global tracer -// */ -// static Tracer global() { -// return TracerProviderHelper.global(); -// } -// -// /** -// * Register a global tracer, behavior depends on implementation. -// * -// * @param tracer tracer to use as a global tracer -// */ -// -// static void global(Tracer tracer) { -// TracerProviderHelper.global(tracer); -// } -// -// /** -// * Whether this tracer is enabled or not. -// * A no op tracer is disabled. -// * -// * @return {@code true} if this tracer is enabled -// */ -// boolean enabled(); -// -// /** -// * A new span builder to construct {@link io.helidon.tracing.Span}. -// * -// * @param name name of the operation -// * @return a new span builder -// */ -// Span.Builder spanBuilder(String name); -// -// /** -// * Extract parent span context from inbound request, such as from HTTP headers. -// * -// * @param headersProvider provider of headers -// * @return span context of inbound parent span, or empty optional if no span context can be found -// */ -// Optional extract(HeaderProvider headersProvider); -// -// /** -// * Inject current span as a parent for outbound request, such as when invoking HTTP request from a client. -// * -// * @param spanContext current span context -// * @param inboundHeadersProvider provider of inbound headers, may be {@link HeaderProvider#empty()} or headers from original -// * request (if any) -// * @param outboundHeadersConsumer consumer of headers that should be propagated to remote endpoint -// */ -// void inject(SpanContext spanContext, HeaderProvider inboundHeadersProvider, HeaderConsumer outboundHeadersConsumer); -// -// /** -// * Access the underlying tracer by specific type. -// * This is a dangerous operation that will succeed only if the tracer is of expected type. This practically -// * removes abstraction capabilities of this API. -// * -// * @param tracerClass type to access -// * @return instance of the tracer -// * @param type of the tracer -// * @throws java.lang.IllegalArgumentException in case the tracer cannot provide the expected type -// */ -// default T unwrap(Class tracerClass) { -// try { -// return tracerClass.cast(this); -// } catch (ClassCastException e) { -// throw new IllegalArgumentException("This tracer is not compatible with " + tracerClass.getName()); -// } -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java deleted file mode 100644 index 9515df93034..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeTracingConfig.java +++ /dev/null @@ -1,244 +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.pico.builder.config.fakes.config; - -import java.util.Map; - -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka TracingConfig. - * - * Tracing configuration that contains traced components (such as WebServer, Security) and their traced spans and span logs. - * Spans can be renamed through configuration, components, spans and span logs may be disabled through this configuration. - */ -@ConfigBean(key = "tracing") -public interface FakeTracingConfig extends FakeTraceableConfig { -// /** -// * Traced config that is enabled for all components, spans and logs. -// */ -// FakeTracingConfig ENABLED = FakeTracingConfig.builder().build(); -// /** -// * Traced conifg that is disabled for all components, spans and logs. -// */ -// FakeTracingConfig DISABLED = FakeTracingConfig.builder().enabled(false).build(); - -// /** -// * A new traced configuration. -// * -// * @param name name of this configuration, when created using {@link FakeTracingConfig.Builder}, -// * the name is {@code helidon} -// */ -// protected FakeTracingConfig(String name) { -// super(name); -// } -// -// /** -// * Configuration of a traced component. -// * -// * @param componentName name of the component -// * @return component tracing configuration or empty if defaults should be used -// */ -// protected abstract Optional getComponent(String componentName); -// -// /** -// * Configuration of a traced component. -// * -// * @param componentName name of the component -// * @return component tracing configuration if configured, or an enabled component configuration -// */ -// public ComponentTracingConfig component(String componentName) { -// return component(componentName, true); -// } - - @Singular("component") // Builder::addComponent(String component); Impl::getComponent(String component); - Map components(); - -// /** -// * Configuration of a traced component. -// * -// * @param componentName name of the component -// * @param enabledByDefault whether the component should be enabled or disabled in case it is not configured -// * @return component tracing configuration if configured, or an enabled/disabled component configuration depending on -// * {@code enabledByDefault} -// */ -// public ComponentTracingConfig component(String componentName, boolean enabledByDefault) { -// if (enabled()) { -// return getComponent(componentName) -// .orElseGet(() -> enabledByDefault ? ComponentTracingConfig.ENABLED : ComponentTracingConfig.DISABLED); -// } -// -// return ComponentTracingConfig.DISABLED; -// } -// -// @Override -// public String toString() { -// return "TracingConfig(" + name() + ")"; -// } -// -// /** -// * Create new tracing configuration based on the provided config. -// * -// * @param config configuration of tracing -// * @return tracing configuration -// */ -// public static FakeTracingConfig create(Config config) { -// return builder().config(config).build(); -// } -// -// /** -// * A fluent API builder for tracing configuration. -// * @return a new builder instance -// */ -// public static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Merge two configurations together. -// * The result will combine configuration from both configurations. In case -// * of conflicts, the {@code newer} wins. -// * -// * @param older older instance to merge -// * @param newer newer (more significant) instance to merge -// * @return a new configuration combining odler and newer -// */ -// public static FakeTracingConfig merge(FakeTracingConfig older, FakeTracingConfig newer) { -// return new FakeTracingConfig(newer.name()) { -// @Override -// public Optional getComponent(String componentName) { -// Optional newerComponent = newer.getComponent(componentName); -// Optional olderComponent = older.getComponent(componentName); -// -// // both configured -// if (newerComponent.isPresent() && olderComponent.isPresent()) { -// return Optional.of(ComponentTracingConfig.merge(olderComponent.get(), newerComponent.get())); -// } -// -// // only newer configured -// if (newerComponent.isPresent()) { -// return newerComponent; -// } -// -// // only older configured -// return olderComponent; -// } -// -// @Override -// public Optional isEnabled() { -// return newer.isEnabled() -// .or(older::isEnabled); -// } -// }; -// } -// -// /** -// * Return configuration of a specific span. -// * This is a shortcut method to {@link #component(String)} and -// * {@link ComponentTracingConfig#span(String)}. -// * -// * @param component component, such as "web-server", "security" -// * @param spanName name of the span, such as "HTTP Request", "security:atn" -// * @return configuration of the span if present in this traced system configuration -// */ -// public SpanTracingConfig spanConfig(String component, String spanName) { -// return component(component).span(spanName); -// } - -// /** -// * Fluent API builder for {@link FakeTracingConfig}. -// */ -// public static final class Builder implements io.helidon.common.Builder { -// private final Map components = new HashMap<>(); -// private Optional enabled = Optional.empty(); -// -// private Builder() { -// } -// -// @Override -// public FakeTracingConfig build() { -// return new RootTracingConfig("helidon", new HashMap<>(components), enabled); -// } -// -// /** -// * Update this builder from configuration. -// * -// * @param config Config with tracing configuration -// * @return updated builder instance -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// Config compConfig = config.get("components"); -// compConfig.asNodeList() -// .ifPresent(compList -> { -// compList.forEach(componentConfig -> addComponent(ComponentTracingConfig.create(componentConfig.name(), -// componentConfig))); -// }); -// -// return this; -// } -// -// /** -// * Add a traced component configuration. -// * -// * @param component configuration of this component's tracing -// * @return updated builder instance -// */ -// public Builder addComponent(ComponentTracingConfig component) { -// components.put(component.name(), component); -// return this; -// } -// -// /** -// * Whether overall tracing is enabled. -// * If tracing is disabled on this level, all traced components and spans are disabled - even if explicitly configured -// * as enabled. -// * -// * @param enabled set to {@code false} to disable tracing for any component and span -// * @return updated builder instance -// */ -// public Builder enabled(boolean enabled) { -// this.enabled = Optional.of(enabled); -// return this; -// } -// } -// -// static final class RootTracingConfig extends FakeTracingConfig { -// private final Map components; -// private final Optional enabled; -// -// RootTracingConfig(String name, -// Map components, -// Optional enabled) { -// super(name); -// this.components = components; -// this.enabled = enabled; -// } -// -// @Override -// public Optional getComponent(String componentName) { -// return Optional.ofNullable(components.get(componentName)); -// } -// -// @Override -// public Optional isEnabled() { -// return enabled; -// } -// -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java deleted file mode 100644 index 5f1213c1484..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeWebServerTlsConfig.java +++ /dev/null @@ -1,438 +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.pico.builder.config.fakes.config; - -import java.security.SecureRandom; -import java.util.Collection; -import java.util.Random; -import java.util.Set; - -import javax.net.ssl.SSLContext; - -import io.helidon.common.LazyValue; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.config.ConfigBean; - -/** - * aka WebServerTls. - * - * A class wrapping transport layer security (TLS) configuration for - * WebServer sockets. - */ -@ConfigBean -public interface FakeWebServerTlsConfig { - String PROTOCOL = "TLS"; - // secure random cannot be stored in native image, it must be initialized at runtime - LazyValue RANDOM = LazyValue.create(SecureRandom::new); - - /** - * This constant is a context classifier for the x509 client certificate if it is present. Callers may use this - * constant to lookup the client certificate associated with the current request context. - */ - String CLIENT_X509_CERTIFICATE = FakeWebServerTlsConfig.class.getName() + ".client-x509-certificate"; - -// private final Set enabledTlsProtocols; -// private final Set cipherSuite; -// private final SSLContext sslContext; -// private final boolean enabled; -// private final ClientAuthentication clientAuth; -// -// private FakeWebServerTlsConfigBean(Builder builder) { -// this.enabledTlsProtocols = Set.copyOf(builder.enabledTlsProtocols); -// this.cipherSuite = builder.cipherSuite; -// this.sslContext = builder.sslContext; -// this.enabled = (null != sslContext); -// this.clientAuth = builder.clientAuth; -// } -// -// /** -// * A fluent API builder for {@link FakeWebServerTlsConfigBean}. -// * -// * @return a new builder instance -// */ -// public static Builder builder() { -// return new Builder(); -// } -// -// /** -// * Create TLS configuration from config. -// * -// * @param config located on the node of the tls configuration (usually this is {@code ssl}) -// * @return a new TLS configuration -// */ -// public static FakeWebServerTlsConfigBean create(Config config) { -// return builder().config(config).build(); -// } -// - - Collection enabledTlsProtocols(); -// { -// return enabledTlsProtocols; -// } -// - - SSLContext sslContext(); -// { -// return sslContext; -// } - -// ClientAuthentication clientAuth() { -// return clientAuth; -// } - - @Singular("cipher") - Set cipherSuite(); -// { -// return cipherSuite; -// } - - /** - * Whether this TLS config has security enabled (and the socket is going to be - * protected by one of the TLS protocols), or no (and the socket is going to be plain). - * - * @return {@code true} if this configuration represents a TLS configuration, {@code false} for plain configuration - */ - boolean enabled(); -// { -// return enabled; -// } -// -// /** -// * Fluent API builder for {@link FakeWebServerTlsConfigBean}. -// */ -// @Configured -// public static class Builder implements io.helidon.common.Builder { -// private final Set enabledTlsProtocols = new HashSet<>(); -// -// private SSLContext sslContext; -// private FakeKeyConfig privateKeyConfig; -// private FakeKeyConfig trustConfig; -// private long sessionCacheSize; -// private long sessionTimeoutSeconds; -// -// private boolean enabled; -// private Boolean explicitEnabled; -// private ClientAuthentication clientAuth; -// private Set cipherSuite = Set.of(); -// -// private Builder() { -// clientAuth = ClientAuthentication.NONE; -// } -// -// @Override -// public FakeWebServerTlsConfigBean build() { -// boolean enabled; -// -// if (null == explicitEnabled) { -// enabled = this.enabled; -// } else { -// enabled = explicitEnabled; -// } -// -// if (!enabled) { -// this.sslContext = null; -// // ssl is disabled -// return new FakeWebServerTlsConfigBean(this); -// } -// -// if (null == sslContext) { -// // no explicit ssl context, build it using private key and trust store -// sslContext = newSSLContext(); -// } -// -// return new FakeWebServerTlsConfigBean(this); -// } -// -// /** -// * Update this builder from configuration. -// * -// * @param config config on the node of SSL configuration -// * @return this builder -// */ -// public Builder config(Config config) { -// config.get("enabled").asBoolean().ifPresent(this::enabled); -// -// if (explicitEnabled != null && !explicitEnabled) { -// return this; -// } -// -// config.get("client-auth").asString().ifPresent(this::clientAuth); -// config.get("private-key") -// .ifExists(it -> privateKey(FakeKeyConfig.create(it))); -// -// config.get("trust") -// .ifExists(it -> trust(FakeKeyConfig.create(it))); -// -// config.get("protocols").asList(String.class).ifPresent(this::enabledProtocols); -// config.get("session-cache-size").asLong().ifPresent(this::sessionCacheSize); -// config.get("cipher-suite").asList(String.class).ifPresent(this::allowedCipherSuite); -// DeprecatedConfig.get(config, "session-timeout-seconds", "session-timeout") -// .asLong() -// .ifPresent(this::sessionTimeoutSeconds); -// -// return this; -// } -// -// private void clientAuth(String it) { -// clientAuth(ClientAuthentication.valueOf(it.toUpperCase())); -// } -// -// /** -// * Configures whether client authentication will be required or not. -// * -// * @param clientAuth client authentication -// * @return this builder -// */ -// @ConfiguredOption("none") -// public Builder clientAuth(ClientAuthentication clientAuth) { -// this.clientAuth = Objects.requireNonNull(clientAuth); -// return this; -// } -// -// /** -// * Configures a {@link SSLContext} to use with the server socket. If not {@code null} then -// * the server enforces an SSL communication. -// * -// * @param context a SSL context to use -// * @return this builder -// */ -// public Builder sslContext(SSLContext context) { -// this.enabled = true; -// this.sslContext = context; -// return this; -// } -// -// /** -// * Configures the TLS protocols to enable with the server socket. -// * @param protocols protocols to enable, if empty, enables defaults -// * -// * @return this builder -// * @throws java.lang.NullPointerException in case the protocols is null -// */ -// public Builder enabledProtocols(String... protocols) { -// return enabledProtocols(Arrays.asList(Objects.requireNonNull(protocols))); -// } -// -// /** -// * Configures the TLS protocols to enable with the server socket. -// * -// * @param protocols protocols to enable, if empty enables -// * the default protocols -// * @return this builder -// * @throws java.lang.NullPointerException in case the protocols is null -// */ -// public Builder enabledProtocols(Collection protocols) { -// Objects.requireNonNull(protocols); -// -// this.enabledTlsProtocols.clear(); -// this.enabledTlsProtocols.addAll(protocols); -// return this; -// } -// -// /** -// * Configure private key to use for SSL context. -// * -// * @param privateKeyConfig the required private key configuration parameter -// * @return this builder -// */ -// @ConfiguredOption(required = true) -// public Builder privateKey(FakeKeyConfig privateKeyConfig) { -// // setting private key, need to reset ssl context -// this.enabled = true; -// this.sslContext = null; -// this.privateKeyConfig = Objects.requireNonNull(privateKeyConfig); -// return this; -// } -// -// /** -// * Configure private key to use for SSL context. -// * -// * @param privateKeyConfigBuilder the required private key configuration parameter -// * @return this builder -// */ -// public Builder privateKey(Supplier privateKeyConfigBuilder) { -// return privateKey(privateKeyConfigBuilder.get()); -// } -// -// /** -// * Set the trust key configuration to be used to validate certificates. -// * -// * @param trustConfig the trust configuration -// * @return this builder -// */ -// @ConfiguredOption -// public Builder trust(FakeKeyConfig trustConfig) { -// // setting explicit trust, need to reset ssl context -// this.enabled = true; -// this.sslContext = null; -// this.trustConfig = Objects.requireNonNull(trustConfig); -// return this; -// } -// -// /** -// * Set the trust key configuration to be used to validate certificates. -// * -// * @param trustConfigBuilder the trust configuration builder -// * @return this builder -// */ -// public Builder trust(Supplier trustConfigBuilder) { -// return trust(trustConfigBuilder.get()); -// } -// -// /** -// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the -// * default value. -// * -// * @param sessionCacheSize the session cache size -// * @return this builder -// */ -// @ConfiguredOption -// public Builder sessionCacheSize(long sessionCacheSize) { -// this.sessionCacheSize = sessionCacheSize; -// return this; -// } -// -// /** -// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the -// * default value. -// * -// * @param sessionTimeout the session timeout -// * @return this builder -// */ -// @ConfiguredOption -// public Builder sessionTimeoutSeconds(long sessionTimeout) { -// this.sessionTimeoutSeconds = sessionTimeout; -// return this; -// } -// -// /** -// * Set the timeout for the cached SSL session objects. {@code 0} to use the -// * default value. -// * -// * @param timeout the session timeout amount -// * @param unit the session timeout time unit -// * @return this builder -// */ -// public Builder sessionTimeout(long timeout, TimeUnit unit) { -// this.sessionTimeoutSeconds = unit.toSeconds(timeout); -// return this; -// } -// -// /** -// * Set allowed cipher suite. If an empty collection is set, an exception is thrown since -// * it is required to support at least some ciphers. -// * -// * @param cipherSuite allowed cipher suite -// * @return an updated builder -// */ -// @ConfiguredOption(key = "cipher-suite") -// public Builder allowedCipherSuite(List cipherSuite) { -// Objects.requireNonNull(cipherSuite); -// if (cipherSuite.isEmpty()) { -// throw new IllegalStateException("Allowed cipher suite has to have at least one cipher specified"); -// } -// this.cipherSuite = Set.copyOf(cipherSuite); -// return this; -// } -// -// /** -// * Whether the TLS config should be enabled or not. -// * -// * @param enabled configure to {@code false} to disable SSL context (and SSL support on the server) -// * @return this builder -// */ -// @ConfiguredOption(description = "Can be used to disable TLS even if keys are configured.", value = "true") -// public Builder enabled(boolean enabled) { -// this.enabled = enabled; -// this.explicitEnabled = enabled; -// return this; -// } -// -// private SSLContext newSSLContext() { -// try { -// if (null == privateKeyConfig) { -// throw new IllegalStateException("Private key must be configured when SSL is enabled."); -// } -// KeyManagerFactory kmf = buildKmf(this.privateKeyConfig); -// TrustManagerFactory tmf = buildTmf(this.trustConfig); -// -// // Initialize the SSLContext to work with our key managers. -// SSLContext ctx = SSLContext.getInstance(PROTOCOL); -// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); -// -// SSLSessionContext sessCtx = ctx.getServerSessionContext(); -// if (sessionCacheSize > 0) { -// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); -// } -// if (this.sessionTimeoutSeconds > 0) { -// sessCtx.setSessionTimeout((int) Math.min(sessionTimeoutSeconds, Integer.MAX_VALUE)); -// } -// return ctx; -// } catch (IOException | GeneralSecurityException e) { -// throw new IllegalStateException("Failed to build server SSL Context!", e); -// } -// } -// -// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { -// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); -// if (algorithm == null) { -// algorithm = "SunX509"; -// } -// -// byte[] passwordBytes = new byte[64]; -// RANDOM.get().nextBytes(passwordBytes); -// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// ks.setKeyEntry("key", -// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), -// password, -// privateKeyConfig.certChain().toArray(new Certificate[0])); -// -// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); -// kmf.init(ks, password); -// -// return kmf; -// } -// -// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) -// throws IOException, GeneralSecurityException { -// List certs; -// -// if (trustConfig == null) { -// certs = List.of(); -// } else { -// certs = trustConfig.certs(); -// } -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// -// int i = 1; -// for (X509Certificate cert : certs) { -// ks.setCertificateEntry(String.valueOf(i), cert); -// i++; -// } -// -// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); -// tmf.init(ks); -// return tmf; -// } -// } -// -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java deleted file mode 100644 index c674fed80e4..00000000000 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/SSLContextConfig.java +++ /dev/null @@ -1,201 +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.pico.builder.config.fakes.config; - -import java.util.Random; - -import io.helidon.pico.builder.Builder; - -/** - * aka SSLContextBuilder. - */ -@Builder -public interface SSLContextConfig { - - String PROTOCOL = "TLS"; - Random RANDOM = new Random(); - -// private FakeKeyConfig privateKeyConfig; -// private FakeKeyConfig trustConfig; -// private long sessionCacheSize; -// private long sessionTimeout; -// -// private SSLContextConfig() { -// } -// - -// /** -// * Creates a builder of the {@link javax.net.ssl.SSLContext}. -// * -// * @param privateKeyConfig the required private key configuration parameter -// * @return this builder -// */ -// public static SSLContextConfig create(FakeKeyConfig privateKeyConfig) { -// return new SSLContextConfig().privateKeyConfig(privateKeyConfig); -// } - -// /** -// * Creates {@link javax.net.ssl.SSLContext} from the provided configuration. -// * -// * @param sslConfig the ssl configuration -// * @return a built {@link javax.net.ssl.SSLContext} -// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or -// * a {@link java.security.GeneralSecurityException} -// */ -// static SSLContext create(Config sslConfig) { -// return new SSLContextConfig().privateKeyConfig(FakeKeyConfig.create(sslConfig.get("private-key"))) -// .sessionCacheSize(sslConfig.get("session-cache-size").asInt().orElse(0)) -// .sessionTimeout(sslConfig.get("session-timeout").asInt().orElse(0)) -// .trustConfig(FakeKeyConfig.create(sslConfig.get("trust"))) -// .build(); -// } -// -// private SSLContextConfig privateKeyConfig(FakeKeyConfig privateKeyConfig) { -// this.privateKeyConfig = privateKeyConfig; -// return this; -// } - - FakeKeyConfig privateKeyConfig(); - -// -// /** -// * Set the trust key configuration to be used to validate certificates. -// * -// * @param trustConfig the trust configuration -// * @return an updated builder -// */ -// public SSLContextConfig trustConfig(FakeKeyConfig trustConfig) { -// this.trustConfig = trustConfig; -// return this; -// } - - FakeKeyConfig trustConfig(); - -// /** -// * Set the size of the cache used for storing SSL session objects. {@code 0} to use the -// * default value. -// * -// * @param sessionCacheSize the session cache size -// * @return an updated builder -// */ -// public SSLContextConfig sessionCacheSize(long sessionCacheSize) { -// this.sessionCacheSize = sessionCacheSize; -// return this; -// } - - long sessionCacheSize(); - -// /** -// * Set the timeout for the cached SSL session objects, in seconds. {@code 0} to use the -// * default value. -// * -// * @param sessionTimeout the session timeout -// * @return an updated builder -// */ -// public SSLContextConfig sessionTimeout(long sessionTimeout) { -// this.sessionTimeout = sessionTimeout; -// return this; -// } - - long sessionTimeout(); - -// /** -// * Create new {@code {@link javax.net.ssl.SSLContext}} instance with configured settings. -// * -// * @return the SSL Context built instance -// * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link java.io.IOException} or -// * a {@link java.security.GeneralSecurityException} -// */ -// public SSLContext build() { -// Objects.requireNonNull(privateKeyConfig, "The private key config must be set!"); -// -// try { -// return newSSLContext(privateKeyConfig, trustConfig, sessionCacheSize, sessionTimeout); -// } catch (IOException | GeneralSecurityException e) { -// throw new IllegalStateException("Building of the SSLContext of unsuccessful!", e); -// } -// } - -// private static SSLContext newSSLContext(FakeKeyConfig privateKeyConfig, -// FakeKeyConfig trustConfig, -// long sessionCacheSize, -// long sessionTimeout) -// throws IOException, GeneralSecurityException { -// KeyManagerFactory kmf = buildKmf(privateKeyConfig); -// TrustManagerFactory tmf = buildTmf(trustConfig); -// -// // Initialize the SSLContext to work with our key managers. -// SSLContext ctx = SSLContext.getInstance(PROTOCOL); -// ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); -// -// SSLSessionContext sessCtx = ctx.getServerSessionContext(); -// if (sessionCacheSize > 0) { -// sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE)); -// } -// if (sessionTimeout > 0) { -// sessCtx.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE)); -// } -// return ctx; -// } -// -// private static KeyManagerFactory buildKmf(FakeKeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { -// String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); -// if (algorithm == null) { -// algorithm = "SunX509"; -// } -// -// byte[] passwordBytes = new byte[64]; -// RANDOM.nextBytes(passwordBytes); -// char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// ks.setKeyEntry("key", -// privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), -// password, -// privateKeyConfig.certChain().toArray(new Certificate[0])); -// -// KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); -// kmf.init(ks, password); -// -// return kmf; -// } -// -// private static TrustManagerFactory buildTmf(FakeKeyConfig trustConfig) -// throws IOException, GeneralSecurityException { -// List certs; -// -// if (trustConfig == null) { -// certs = List.of(); -// } else { -// certs = trustConfig.certs(); -// } -// -// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); -// ks.load(null, null); -// -// int i = 1; -// for (X509Certificate cert : certs) { -// ks.setCertificateEntry(String.valueOf(i), cert); -// i++; -// } -// -// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); -// tmf.init(ks); -// return tmf; -// } -} diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java index 2636622a275..6a260de4a14 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ClientConfig.java @@ -14,23 +14,40 @@ * limitations under the License. */ -package io.helidon.pico.builder.config.test.testsubjects; +package io.helidon.pico.builder.config.testsubjects; import java.util.Map; import io.helidon.config.metadata.ConfiguredOption; import io.helidon.pico.builder.config.ConfigBean; -import io.helidon.pico.builder.config.testsubjects.CommonConfig; +/** + * For testing purpose. + */ @ConfigBean(drivesActivation = false) public interface ClientConfig extends CommonConfig { + /** + * For testing purpose. + * + * @return for testing purposes + */ @ConfiguredOption("default") @Override String name(); + /** + * For testing purpose. + * + * @return for testing purposes + */ int serverPort(); + /** + * For testing purpose. + * + * @return for testing purposes + */ Map headers(); } diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java index 8c6d70d2d86..fcd20417939 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java @@ -21,16 +21,39 @@ import io.helidon.config.metadata.ConfiguredOption; import io.helidon.pico.builder.config.ConfigBean; +/** + * For testing purpose. + */ @ConfigBean public interface CommonConfig { + /** + * For testing purpose. + * + * @return for testing purposes + */ String name(); + /** + * For testing purpose. + * + * @return for testing purposes + */ @ConfiguredOption(required = true) int port(); + /** + * For testing purpose. + * + * @return for testing purposes + */ List cipherSuites(); + /** + * For testing purpose. + * + * @return for testing purposes + */ char[] pwd(); } diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java index 9dcd7bf600e..f5a569a08ee 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/ServerConfig.java @@ -21,13 +21,26 @@ import io.helidon.config.metadata.ConfiguredOption; import io.helidon.pico.builder.config.ConfigBean; +/** + * For testing purpose. + */ @ConfigBean(atLeastOne = true) public interface ServerConfig extends CommonConfig { + /** + * For testing purpose. + * + * @return for testing purposes + */ @ConfiguredOption("default") @Override String name(); + /** + * For testing purpose. + * + * @return for testing purposes + */ Optional description(); } diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/package-info.java similarity index 78% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java rename to pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/package-info.java index 238f795421a..0c9849e207d 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/config/FakeNettyClientAuth.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/package-info.java @@ -14,13 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.config.fakes.config; - -public enum FakeNettyClientAuth { - NONE, - OPTIONAL, - REQUIRE; - - private FakeNettyClientAuth() { - } -} +/** + * ConfigBean test subjects. + */ +package io.helidon.pico.builder.config.testsubjects; diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeClientAuth.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeNettyClientAuth.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeRoutingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerLifecycle.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSocketConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanLogTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTraceableConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracer.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracer.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracer.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServer.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/WebServer.java similarity index 100% rename from pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/fakes/WebServer.java rename to pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/WebServer.java From f7e72e0e66157e105287cbab8fc6f412932e897b Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 22 Nov 2022 10:47:57 -0500 Subject: [PATCH 25/36] Promote ConfigMapper and ConfigMapperProvider to common level SPI. Then extend ConfigBeanMapper to be a specialization of ConfigMapperProvider --- .../helidon/common/config/ConfigHolder.java | 4 +- .../common/config/spi/ConfigMapper.java | 42 +++++++++++++++++++ .../config/spi/ConfigMapperProvider.java | 40 ++++++++++++++++++ common/config/src/main/java/module-info.java | 1 + config/config/etc/spotbugs/exclude.xml | 10 +++++ .../io/helidon/config/spi/ConfigMapper.java | 7 +++- .../config/spi/ConfigMapperProvider.java | 5 ++- config/config/src/main/java/module-info.java | 5 +-- .../pico/builder/config/package-info.java | 2 +- .../builder/config/spi/ConfigBeanMapper.java | 10 ++--- .../config/spi/ConfigBeanMapperHolder.java | 2 +- 11 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java create mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java diff --git a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java index d84dc6e3b59..753c66fefb7 100644 --- a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java +++ b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java @@ -33,7 +33,7 @@ * (2) programmatically via the {@link #config(io.helidon.common.config.Config)} method. The {@link #config()} method will * apply the following strategy to resolve and cache the global config instance: *

    - *
  1. if the instance is already been established and cached then use it.
  2. + *
  3. if the instance has already been established and cached then use it.
  4. *
  5. if the instance has programmatically been set then use it - this is the same as the cached instance.
  6. *
  7. use the service loader to resolve the config instance, and if found then cache it.
  8. *
@@ -42,7 +42,7 @@ * method. *

* Note that this class is not thread safe. If the global configuration must be set programmatically then it should therefore - * be set on the main thread typically early in the jvm lifecycle. + * be set on the main thread, and typically early in the jvm lifecycle. * * @see io.helidon.common.config.spi.ConfigProvider */ diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java new file mode 100644 index 00000000000..5dffb4e8b7d --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java @@ -0,0 +1,42 @@ +/* + * 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.common.config.spi; + +import io.helidon.common.config.Config; +import io.helidon.common.config.ConfigException; + +/** + * Config mapper is provided to {@link ConfigMapperProvider} to help transformation of + * complex structures. + * + * @param the Config type + */ +@FunctionalInterface +public interface ConfigMapper { + + /** + * Converts the specified {@code Config} node to the target type. + * + * @param config config node to be transformed + * @param type type to which the config node is to be transformed + * @param type to which the config node is to be transformed + * @return transformed value of type {@code T}; never returns {@code null} + * @throws io.helidon.common.config.ConfigException if any issues occur in mapping + */ + T map(C config, Class type) throws ConfigException; + +} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java new file mode 100644 index 00000000000..3ec6a715764 --- /dev/null +++ b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java @@ -0,0 +1,40 @@ +/* + * 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.common.config.spi; + +import java.util.Map; +import java.util.function.Function; + +import io.helidon.common.config.Config; + +/** + * Provides mapping functions that convert a {@code Config} + * subtree to specific Java types. + * + * @param the Config type + */ +@FunctionalInterface +public interface ConfigMapperProvider { + + /** + * Returns a map of mapper functions associated with appropriate target type ({@code Class}. + * + * @return a map of config mapper functions, never {@code null} + */ + Map, Function> mappers(); + +} diff --git a/common/config/src/main/java/module-info.java b/common/config/src/main/java/module-info.java index 86500ceda0f..74bcf4c599e 100644 --- a/common/config/src/main/java/module-info.java +++ b/common/config/src/main/java/module-info.java @@ -20,6 +20,7 @@ module io.helidon.common.config { requires io.helidon.common; + uses io.helidon.common.config.spi.ConfigMapperProvider; uses io.helidon.common.config.spi.ConfigProvider; exports io.helidon.common.config; diff --git a/config/config/etc/spotbugs/exclude.xml b/config/config/etc/spotbugs/exclude.xml index 5e1451958f9..535dd1c158c 100644 --- a/config/config/etc/spotbugs/exclude.xml +++ b/config/config/etc/spotbugs/exclude.xml @@ -103,5 +103,15 @@ + + + + + + + + + + diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java index b08d80456d5..067cf3768d4 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.helidon.config.spi; import java.lang.reflect.Type; @@ -26,7 +27,8 @@ * Config mapper is provided to {@link ConfigMapperProvider} to help transformation of * complex structures. */ -public interface ConfigMapper { +public interface ConfigMapper extends io.helidon.common.config.spi.ConfigMapper { + /** * Convert the specified {@code Config} node into the target type specified by {@link GenericType}. * You can use {@link GenericType#create(Type)} if needed to wrap a parametrized type. @@ -58,6 +60,7 @@ public interface ConfigMapper { * @throws ConfigMappingException in case the mapper fails to map the existing configuration value * to an instance of a given Java type */ + @Override T map(Config config, Class type) throws MissingValueException, ConfigMappingException; /** diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java index 86f8d140cef..d43eea3fce1 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. + * Copyright (c) 2017, 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. @@ -43,7 +43,7 @@ * @see Config.Builder#disableMapperServices() */ @FunctionalInterface -public interface ConfigMapperProvider { +public interface ConfigMapperProvider extends io.helidon.common.config.spi.ConfigMapperProvider { /** * Default priority of the mapper provider if registered by {@link Config.Builder} automatically. */ @@ -59,6 +59,7 @@ public interface ConfigMapperProvider { * @return a map of config mapper functions, never {@code null}, though this may return an empty map if * {@link #mapper(Class)} is used instead */ + @Override Map, Function> mappers(); /** diff --git a/config/config/src/main/java/module-info.java b/config/config/src/main/java/module-info.java index da42f7919f1..13ba3775edb 100644 --- a/config/config/src/main/java/module-info.java +++ b/config/config/src/main/java/module-info.java @@ -14,8 +14,6 @@ * limitations under the License. */ -import io.helidon.config.PropertiesConfigParser; - /** * Helidon SE Config module. * @@ -43,7 +41,8 @@ uses io.helidon.config.spi.PollingStrategyProvider; uses io.helidon.config.spi.ChangeWatcherProvider; - provides io.helidon.config.spi.ConfigParser with PropertiesConfigParser; + provides io.helidon.config.spi.ConfigParser + with io.helidon.config.PropertiesConfigParser; // needed when running with modules - to make private methods accessible opens io.helidon.config to weld.core.impl, io.helidon.microprofile.cdi; diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java index bf8cfa090f8..fa8c61aee55 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/package-info.java @@ -15,6 +15,6 @@ */ /** - * Helidon Pico Config Builder API. + * Helidon Pico ConfigBean Builder API. */ package io.helidon.pico.builder.config; diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java index a71e423257d..c268a737b7c 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java @@ -17,24 +17,24 @@ package io.helidon.pico.builder.config.spi; import io.helidon.common.config.Config; +import io.helidon.common.config.spi.ConfigMapper; /** * Maps a {@link io.helidon.common.config.Config} instance to a newly created * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type instance. * - * @param the config bean type + * @param the config type */ -@FunctionalInterface -public interface ConfigBeanMapper { +public interface ConfigBeanMapper extends ConfigMapper { /** * Translate the provided configuration into the appropriate config bean for this service type. * * @param cfg the config * @param configBeanType the config bean type + * @param the config bean type * @return the config bean generated */ - CB toConfigBean(Config cfg, - Class configBeanType); + T map(T cfg, Class configBeanType); } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java index f287390a360..d27d863b003 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java @@ -46,7 +46,7 @@ private ConfigBeanMapperHolder() { * @return the config bean mapper */ @SuppressWarnings({"rawTypes", "unchecked"}) - public static Optional> configBeanMapperFor(Class configBeanType) { + public static Optional configBeanMapperFor(Class configBeanType) { return (Optional) INSTANCE.get(); } From 925da7428abf274b6711404c1985d87557ebcc96 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 22 Nov 2022 11:11:05 -0500 Subject: [PATCH 26/36] A few tweaks over the last push. --- .../ConfigBeanBuilderValidatorProvider.java | 1 + .../builder/config/spi/ConfigBeanMapper.java | 4 ++- .../config/spi/ConfigBeanMapperProvider.java | 1 + .../config/spi/ConfigResolverProvider.java | 1 + pico/builder-config/tests/configbean/pom.xml | 32 ------------------- 5 files changed, 6 insertions(+), 33 deletions(-) diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java index ece42d72d74..43789b7c5c7 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidatorProvider.java @@ -21,6 +21,7 @@ * * @see ConfigBeanBuilderValidatorHolder */ +@FunctionalInterface public interface ConfigBeanBuilderValidatorProvider { /** diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java index c268a737b7c..911938639ce 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java @@ -25,6 +25,7 @@ * * @param the config type */ +@FunctionalInterface public interface ConfigBeanMapper extends ConfigMapper { /** @@ -35,6 +36,7 @@ public interface ConfigBeanMapper extends ConfigMapper { * @param the config bean type * @return the config bean generated */ - T map(T cfg, Class configBeanType); + @Override + T map(C cfg, Class configBeanType); } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java index eac42ff3c4d..2c6b65cde3d 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java @@ -21,6 +21,7 @@ * * @see ConfigBeanMapperHolder */ +@FunctionalInterface public interface ConfigBeanMapperProvider { /** diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java index bc37b31eca9..3fa5c2d8a79 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverProvider.java @@ -19,6 +19,7 @@ /** * Java {@link java.util.ServiceLoader} provider interface to find implementation of {@link ConfigResolver}. */ +@FunctionalInterface public interface ConfigResolverProvider { /** diff --git a/pico/builder-config/tests/configbean/pom.xml b/pico/builder-config/tests/configbean/pom.xml index 76648bbe2dc..5d542baa90e 100644 --- a/pico/builder-config/tests/configbean/pom.xml +++ b/pico/builder-config/tests/configbean/pom.xml @@ -101,41 +101,9 @@ helidon-pico-builder-config-processor ${helidon.version} - - - - - - - - - - - - - - - - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - From e010a87cc2780a919ef36572bded8d6d2985c3ef Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 22 Nov 2022 12:45:35 -0500 Subject: [PATCH 27/36] A few tweaks over the last push. --- config/config/etc/spotbugs/exclude.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config/etc/spotbugs/exclude.xml b/config/config/etc/spotbugs/exclude.xml index 535dd1c158c..2f8695941ca 100644 --- a/config/config/etc/spotbugs/exclude.xml +++ b/config/config/etc/spotbugs/exclude.xml @@ -106,12 +106,12 @@ - + - + From 67de03de36ec4401c0ca7522707c6feac7f4c2d6 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 29 Nov 2022 14:58:06 -0500 Subject: [PATCH 28/36] relocating /pico/builder to /builder --- bom/pom.xml | 31 +++++++++-------- {pico/builder => builder}/README.md | 20 +++++------ {pico/builder => builder}/builder/README.md | 2 +- {pico/builder => builder}/builder/pom.xml | 8 ++--- .../java/io/helidon}/builder/Annotated.java | 2 +- .../io/helidon}/builder/AttributeVisitor.java | 4 +-- .../java/io/helidon}/builder/Builder.java | 2 +- .../io/helidon}/builder/BuilderTrigger.java | 2 +- .../java/io/helidon}/builder/Singular.java | 2 +- .../io/helidon}/builder/package-info.java | 8 ++--- .../builder/spi/RequiredAttributeVisitor.java | 8 ++--- .../io/helidon}/builder/spi/package-info.java | 2 +- .../builder/src/main/java/module-info.java | 8 ++--- {pico/builder => builder}/pom.xml | 12 +++---- .../processor-spi/README.md | 2 +- .../builder => builder}/processor-spi/pom.xml | 13 +++---- .../builder/processor/spi/BuilderCreator.java | 8 ++--- .../processor/spi/DefaultTypeAndBody.java | 2 +- .../processor/spi/DefaultTypeInfo.java | 2 +- .../builder/processor/spi/TypeAndBody.java | 2 +- .../builder/processor/spi/TypeInfo.java | 4 +-- .../processor/spi/TypeInfoCreator.java | 6 ++-- .../builder/processor/spi/package-info.java | 6 ++-- .../src/main/java/module-info.java | 8 ++--- .../processor-tools/README.md | 2 +- .../processor-tools/pom.xml | 16 ++++----- .../builder/processor/tools/BeanUtils.java | 2 +- .../builder/processor/tools/BodyContext.java | 32 ++++++++--------- .../tools/BuilderTemplateHelper.java | 2 +- .../processor/tools/BuilderTypeTools.java | 10 +++--- .../tools/DefaultBuilderCreator.java | 34 +++++++++---------- .../processor/tools/GenerateJavadoc.java | 2 +- .../processor/tools/GenerateMethod.java | 2 +- .../tools/GenerateVisitorSupport.java | 2 +- .../tools/ToStringAnnotationValueVisitor.java | 2 +- .../builder/processor/tools/package-info.java | 2 +- .../src/main/java/module-info.java | 18 +++++----- .../processor/tools/BeanUtilsTest.java | 8 ++--- {pico/builder => builder}/processor/pom.xml | 16 ++++----- .../builder/processor/BuilderProcessor.java | 14 ++++---- .../builder/processor/package-info.java | 4 +-- .../processor/src/main/java/module-info.java | 19 ++++++----- .../builder => builder}/tests/builder/pom.xml | 24 ++++++------- .../helidon}/builder/test/testsubjects/A.java | 4 +-- .../test/testsubjects/AnnotationCase.java | 4 +-- .../test/testsubjects/AnnotationCaseExt.java | 4 +-- .../helidon}/builder/test/testsubjects/B.java | 4 +-- .../helidon}/builder/test/testsubjects/C.java | 4 +-- .../ChildInterfaceIsABuilder.java | 4 +-- .../test/testsubjects/ComplexCase.java | 10 +++--- .../builder/test/testsubjects/Container.java | 6 ++-- .../test/testsubjects/CustomNamed.java | 8 ++--- .../builder/test/testsubjects/EdgeCases.java | 4 +-- .../builder/test/testsubjects/Level0.java | 6 ++-- .../builder/test/testsubjects/Level1.java | 6 ++-- .../builder/test/testsubjects/Level2.java | 12 +++---- .../test/testsubjects/MyConfigBean.java | 6 ++-- .../testsubjects/MyDerivedConfigBean.java | 6 ++-- .../ParentInterfaceNotABuilder.java | 4 +-- .../ParentOfParentInterfaceIsABuilder.java | 6 ++-- .../builder/test/testsubjects/Pickle.java | 6 ++-- .../test/testsubjects/PickleBarrel.java | 8 ++--- .../helidon}/builder/test/testsubjects/T.java | 4 +-- .../test/testsubjects/package-info.java | 2 +- .../builder/src/main/java/module-info.java | 6 ++-- .../builder}/test/AnnotationCaseTest.java | 6 ++-- .../builder}/test/ComplexCaseTest.java | 6 ++-- .../builder}/test/CustomNamedTest.java | 6 ++-- .../test/DependsOnAllBuilderTest.java | 2 +- .../builder}/test/DependsOnAllBuilders.java | 14 ++++---- .../helidon/builder}/test/EdgeCasesTest.java | 4 +-- .../io/helidon/builder}/test/LevelTest.java | 20 +++++------ .../builder}/test/MyConfigBeanTest.java | 8 ++--- .../test/MyDerivedConfigBeanTest.java | 6 ++-- .../builder}/test/ParentParentChildTest.java | 6 ++-- .../builder}/test/PickleBarrelTest.java | 10 +++--- .../io/helidon/builder}/test/UsageTest.java | 18 +++++----- .../test/testsubjects/Level0ManualImpl.java | 8 ++--- .../test/testsubjects/Level1ManualImpl.java | 8 ++--- .../test/testsubjects/Level2ManualImpl.java | 10 ++---- .../testsubjects/MyConfigBeanManualImpl.java | 4 +-- {pico/builder => builder}/tests/pom.xml | 10 +++--- pico/builder-config/builder-config/pom.xml | 13 ++++--- .../pico/builder/config/ConfigBean.java | 10 +++--- .../spi/ConfigBeanBuilderValidator.java | 2 +- .../builder/config/spi/ConfigBeanInfo.java | 4 +-- .../config/spi/ConfigResolverMapRequest.java | 2 +- .../config/spi/ConfigResolverRequest.java | 2 +- .../config/spi/GeneratedConfigCommon.java | 4 +-- .../src/main/java/module-info.java | 2 +- pico/builder-config/processor/pom.xml | 4 +-- .../tools/ConfigBeanBuilderCreator.java | 6 ++-- .../processor/src/main/java/module-info.java | 10 +++--- .../tests/ConfigBeanBuilderCreatorTest.java | 2 +- .../configbean/src/main/java/module-info.java | 2 +- .../fakes/FakeComponentTracingConfig.java | 2 +- .../builder/config/fakes/FakeKeyConfig.java | 2 +- .../config/fakes/FakeKeystoreConfig.java | 2 +- .../config/fakes/FakePathTracingConfig.java | 2 +- .../config/fakes/FakeServerConfig.java | 2 +- .../config/fakes/FakeSpanTracingConfig.java | 2 +- .../config/fakes/FakeTracingConfig.java | 2 +- .../config/fakes/FakeWebServerTlsConfig.java | 2 +- .../config/fakes/SSLContextConfig.java | 2 +- pico/pico/pom.xml | 12 +++---- .../io/helidon/pico/ActivationLogEntry.java | 2 +- .../io/helidon/pico/ActivationRequest.java | 2 +- .../io/helidon/pico/ActivationResult.java | 2 +- .../helidon/pico/ContextualServiceQuery.java | 2 +- .../io/helidon/pico/DeActivationRequest.java | 2 +- .../java/io/helidon/pico/DependencyInfo.java | 2 +- .../java/io/helidon/pico/ElementInfo.java | 2 +- .../io/helidon/pico/InjectionPointInfo.java | 2 +- .../java/io/helidon/pico/InjectorOptions.java | 2 +- .../io/helidon/pico/ServiceInfoCriteria.java | 4 +-- pico/pico/src/main/java/module-info.java | 2 +- pico/pom.xml | 1 - pom.xml | 2 +- 118 files changed, 379 insertions(+), 386 deletions(-) rename {pico/builder => builder}/README.md (74%) rename {pico/builder => builder}/builder/README.md (90%) rename {pico/builder => builder}/builder/pom.xml (86%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/Annotated.java (97%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/AttributeVisitor.java (92%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/Builder.java (99%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/BuilderTrigger.java (97%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/Singular.java (98%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/package-info.java (76%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/spi/RequiredAttributeVisitor.java (89%) rename {pico/builder/builder/src/main/java/io/helidon/pico => builder/builder/src/main/java/io/helidon}/builder/spi/package-info.java (94%) rename {pico/builder => builder}/builder/src/main/java/module-info.java (80%) rename {pico/builder => builder}/pom.xml (80%) rename {pico/builder => builder}/processor-spi/README.md (68%) rename {pico/builder => builder}/processor-spi/pom.xml (77%) rename {pico/builder/processor-spi/src/main/java/io/helidon/pico => builder/processor-spi/src/main/java/io/helidon}/builder/processor/spi/BuilderCreator.java (89%) rename {pico/builder/processor-spi/src/main/java/io/helidon/pico => builder/processor-spi/src/main/java/io/helidon}/builder/processor/spi/DefaultTypeAndBody.java (98%) rename {pico/builder/processor-spi/src/main/java/io/helidon/pico => builder/processor-spi/src/main/java/io/helidon}/builder/processor/spi/DefaultTypeInfo.java (99%) rename {pico/builder/processor-spi/src/main/java/io/helidon/pico => builder/processor-spi/src/main/java/io/helidon}/builder/processor/spi/TypeAndBody.java (95%) rename {pico/builder/processor-spi/src/main/java/io/helidon/pico => builder/processor-spi/src/main/java/io/helidon}/builder/processor/spi/TypeInfo.java (93%) rename {pico/builder/processor-spi/src/main/java/io/helidon/pico => builder/processor-spi/src/main/java/io/helidon}/builder/processor/spi/TypeInfoCreator.java (87%) rename {pico/builder/processor-spi/src/main/java/io/helidon/pico => builder/processor-spi/src/main/java/io/helidon}/builder/processor/spi/package-info.java (75%) rename {pico/builder => builder}/processor-spi/src/main/java/module-info.java (79%) rename {pico/builder => builder}/processor-tools/README.md (75%) rename {pico/builder => builder}/processor-tools/pom.xml (82%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/BeanUtils.java (99%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/BodyContext.java (92%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/BuilderTemplateHelper.java (96%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/BuilderTypeTools.java (97%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/DefaultBuilderCreator.java (98%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/GenerateJavadoc.java (99%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/GenerateMethod.java (99%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/GenerateVisitorSupport.java (99%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/ToStringAnnotationValueVisitor.java (99%) rename {pico/builder/processor-tools/src/main/java/io/helidon/pico => builder/processor-tools/src/main/java/io/helidon}/builder/processor/tools/package-info.java (94%) rename {pico/builder => builder}/processor-tools/src/main/java/module-info.java (59%) rename {pico/builder/processor-tools/src/test/java/io/helidon/pico => builder/processor-tools/src/test/java/io/helidon}/builder/processor/tools/BeanUtilsTest.java (96%) rename {pico/builder => builder}/processor/pom.xml (78%) rename {pico/builder/processor/src/main/java/io/helidon/pico => builder/processor/src/main/java/io/helidon}/builder/processor/BuilderProcessor.java (95%) rename {pico/builder/processor/src/main/java/io/helidon/pico => builder/processor/src/main/java/io/helidon}/builder/processor/package-info.java (86%) rename {pico/builder => builder}/processor/src/main/java/module-info.java (58%) rename {pico/builder => builder}/tests/builder/pom.xml (81%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/A.java (89%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/AnnotationCase.java (91%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/AnnotationCaseExt.java (89%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/B.java (89%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/C.java (89%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/ChildInterfaceIsABuilder.java (95%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/ComplexCase.java (92%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/Container.java (88%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/CustomNamed.java (92%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/EdgeCases.java (93%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/Level0.java (88%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/Level1.java (93%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/Level2.java (89%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/MyConfigBean.java (91%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/MyDerivedConfigBean.java (86%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/ParentInterfaceNotABuilder.java (92%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/ParentOfParentInterfaceIsABuilder.java (87%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/Pickle.java (91%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/PickleBarrel.java (85%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/T.java (89%) rename {pico/builder/tests/builder/src/main/java/io/helidon/pico => builder/tests/builder/src/main/java/io/helidon}/builder/test/testsubjects/package-info.java (92%) rename {pico/builder => builder}/tests/builder/src/main/java/module-info.java (87%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/AnnotationCaseTest.java (87%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/ComplexCaseTest.java (90%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/CustomNamedTest.java (92%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/DependsOnAllBuilderTest.java (96%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/DependsOnAllBuilders.java (69%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/EdgeCasesTest.java (92%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/LevelTest.java (92%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/MyConfigBeanTest.java (91%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/MyDerivedConfigBeanTest.java (92%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/ParentParentChildTest.java (93%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/PickleBarrelTest.java (87%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/UsageTest.java (79%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/testsubjects/Level0ManualImpl.java (93%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/testsubjects/Level1ManualImpl.java (95%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/testsubjects/Level2ManualImpl.java (95%) rename {pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api => builder/tests/builder/src/test/java/io/helidon/builder}/test/testsubjects/MyConfigBeanManualImpl.java (97%) rename {pico/builder => builder}/tests/pom.xml (84%) diff --git a/bom/pom.xml b/bom/pom.xml index 0a95049ff32..4c60da75d48 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -1391,37 +1391,37 @@ ${helidon.version} - + - io.helidon.pico - helidon-pico + io.helidon.builder + helidon-builder ${helidon.version} - io.helidon.pico - helidon-pico-types + io.helidon.builder + helidon-builder-processor-spi ${helidon.version} - - - io.helidon.pico.builder - helidon-pico-builder + io.helidon.builder + helidon-builder-processor-tools ${helidon.version} - io.helidon.pico.builder - helidon-pico-builder-processor-spi + io.helidon.builder + helidon-builder-processor ${helidon.version} + + - io.helidon.pico.builder - helidon-pico-builder-processor-tools + io.helidon.pico + helidon-pico ${helidon.version} - io.helidon.pico.builder - helidon-pico-builder-processor + io.helidon.pico + helidon-pico-types ${helidon.version} @@ -1437,6 +1437,7 @@ ${helidon.version} + diff --git a/pico/builder/README.md b/builder/README.md similarity index 74% rename from pico/builder/README.md rename to builder/README.md index 75ec563703b..35f94258158 100644 --- a/pico/builder/README.md +++ b/builder/README.md @@ -1,16 +1,16 @@ -# pico-builder +# builder -The Helidon Pico Builder provides compile-time code generation for fluent builders. It was inspired by [Lombok]([https://projectlombok.org/), but the implementation here in Helidon is different in a few ways: +The Helidon Builder provides compile-time code generation for fluent builders. It was inspired by [Lombok]([https://projectlombok.org/), but the implementation here in Helidon is different in a few ways:

  1. The Builder annotation targets interface or annotation types only. Your interface effectively contains the attributes of your getter as well as serving as the contract for your getter methods.
  2. Generated classes implement your target interface (or annotation) and provide a fluent builder that will always have an implementation of toString(), hashCode(), and equals(). implemented
  3. Generated classes always behave like a SuperBuilder from Lombok. Basically this means that builders can form a hierarchy on the types they target (e.g., Level2 derives from Level1 derives from Level0, etc.).
  4. -
  5. Lombok uses AOP while the Pico Builder generates source code. You can use the Builder annotation (as well as other annotations in the package and ConfiguredOption) to control the naming and other features of what and how the implementation classes are generated and behave.
  6. -
  7. Pico Builders are extensible - you can provide your own implementation of the Builder Processor SPI to customize the generated classes for your situation.
  8. +
  9. Lombok uses AOP while the Helidon Builder generates source code. You can use the Builder annotation (as well as other annotations in the package and ConfiguredOption) to control the naming and other features of what and how the implementation classes are generated and behave.
  10. +
  11. Builders are extensible - you can provide your own implementation of the Builder Processor SPI to customize the generated classes for your situation.
-Supported annotation types (see [builder](./builder/src/main/java/io/helidon/pico/builder) for further details): +Supported annotation types (see [builder](./builder/src/main/java/io/helidon/builder) for further details): * Builder - similar to Lombok's SuperBuilder. * Singular - similar to Lombok's Singular. @@ -18,7 +18,7 @@ Any and all types are supported by the Builder, with special handling for List, however, should only contain getter like methods (i.e., has a non-void return and takes no arguments). All static and default methods are ignored on the target being processed. -The Helidon Pico Builder is completely independent of other parts of Pico. It can therefore be used in a standalone manner. The +The Helidon Builder is independent of other parts of Helidon. It can therefore be used in a standalone manner. The generated implementation class will not require any special module to support those classes - just the types from your interface and standard JRE types are used. This is made possible when your Builder has the requireBuilderLibrary=false. See the javadoc for details. @@ -32,15 +32,15 @@ public interface MyConfigBean { } ``` 2. Annotate your interface definition with Builder, and optionally use ConfiguredOption, Singular, etc. Remember to review the annotation attributes javadoc for any customizations. -3. Compile (using the pico-builder-processor in your annotation classpath). +3. Compile (using the builder-processor in your annotation classpath). The result of this will create (under ./target/generated-sources/annotations): * MyConfigBeanImpl (in the same package as MyConfigBean) that will support multi-inheritance builders named MyConfigBeanImpl.Builder. * Support for toString(), hashCode(), and equals() are always included. * Support for toBuilder(). -* Support for streams (see javadoc for [Builder](./builder/src/main/java/io/helidon/pico/builder/Builder.java)). -* Support for attribute visitors (see [test-builder](./tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/package-info.java)). -* Support for attribute validation (see ConfiguredOption#required() and [builder](./tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/package-info.java)). +* Support for streams (see javadoc for [Builder](./builder/src/main/java/io/helidon/builder/Builder.java)). +* Support for attribute visitors (see [test-builder](./tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java)). +* Support for attribute validation (see ConfiguredOption#required() and [builder](./tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java)). The implementation of the processor also allows for a provider-based extensibility mechanism. diff --git a/pico/builder/builder/README.md b/builder/builder/README.md similarity index 90% rename from pico/builder/builder/README.md rename to builder/builder/README.md index 1d96528cbd4..d8669999e21 100644 --- a/pico/builder/builder/README.md +++ b/builder/builder/README.md @@ -1,4 +1,4 @@ -# pico-builder +# builder This module can either be used compile-time only or at runtime as well depending upon your usage. diff --git a/pico/builder/builder/pom.xml b/builder/builder/pom.xml similarity index 86% rename from pico/builder/builder/pom.xml rename to builder/builder/pom.xml index e53b29f5852..ac358c82929 100644 --- a/pico/builder/builder/pom.xml +++ b/builder/builder/pom.xml @@ -22,15 +22,15 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - io.helidon.pico.builder - helidon-pico-builder-project + io.helidon.builder + helidon-builder-project 4.0.0-SNAPSHOT ../pom.xml 4.0.0 - helidon-pico-builder - Helidon Pico Builder + helidon-builder + Helidon Builder diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/Annotated.java b/builder/builder/src/main/java/io/helidon/builder/Annotated.java similarity index 97% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/Annotated.java rename to builder/builder/src/main/java/io/helidon/builder/Annotated.java index 1ff18c14b19..430fd4d4790 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/Annotated.java +++ b/builder/builder/src/main/java/io/helidon/builder/Annotated.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder; +package io.helidon.builder; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/AttributeVisitor.java b/builder/builder/src/main/java/io/helidon/builder/AttributeVisitor.java similarity index 92% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/AttributeVisitor.java rename to builder/builder/src/main/java/io/helidon/builder/AttributeVisitor.java index 0b4e134ca06..8ba1954f710 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/AttributeVisitor.java +++ b/builder/builder/src/main/java/io/helidon/builder/AttributeVisitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder; +package io.helidon.builder; import java.util.Map; import java.util.function.Supplier; @@ -22,7 +22,7 @@ /** * A functional interface that can be used to visit all attributes of this type. *

- * This type is used when {@link io.helidon.pico.builder.Builder#requireLibraryDependencies()} is used. + * This type is used when {@link Builder#requireLibraryDependencies()} is used. */ @FunctionalInterface public interface AttributeVisitor { diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/Builder.java b/builder/builder/src/main/java/io/helidon/builder/Builder.java similarity index 99% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/Builder.java rename to builder/builder/src/main/java/io/helidon/builder/Builder.java index 9d0948fe2e5..3664bba9c3a 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/Builder.java +++ b/builder/builder/src/main/java/io/helidon/builder/Builder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder; +package io.helidon.builder; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/BuilderTrigger.java b/builder/builder/src/main/java/io/helidon/builder/BuilderTrigger.java similarity index 97% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/BuilderTrigger.java rename to builder/builder/src/main/java/io/helidon/builder/BuilderTrigger.java index 4442318064b..668ea0ffd39 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/BuilderTrigger.java +++ b/builder/builder/src/main/java/io/helidon/builder/BuilderTrigger.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder; +package io.helidon.builder; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/Singular.java b/builder/builder/src/main/java/io/helidon/builder/Singular.java similarity index 98% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/Singular.java rename to builder/builder/src/main/java/io/helidon/builder/Singular.java index c6e8328c4a3..0322013e50d 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/Singular.java +++ b/builder/builder/src/main/java/io/helidon/builder/Singular.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder; +package io.helidon.builder; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/package-info.java b/builder/builder/src/main/java/io/helidon/builder/package-info.java similarity index 76% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/package-info.java rename to builder/builder/src/main/java/io/helidon/builder/package-info.java index 004a5531b13..193eb52e84b 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/package-info.java +++ b/builder/builder/src/main/java/io/helidon/builder/package-info.java @@ -16,10 +16,10 @@ /** * The Builder API consists of a few annotations that can be used to create fluent builders for the types that use - * {@link io.helidon.pico.builder.Builder}, or otherwise one of its kind. The meta annotation - * {@link io.helidon.pico.builder.BuilderTrigger} is used to annotate the annotations that trigger custom-style builders. + * {@link io.helidon.builder.Builder}, or otherwise one of its kind. The meta annotation + * {@link io.helidon.builder.BuilderTrigger} is used to annotate the annotations that trigger custom-style builders. *

- * The {@link io.helidon.pico.builder.Builder} annotation typically is applied to the an interface type, but it can also + * The {@link io.helidon.builder.Builder} annotation typically is applied to the an interface type, but it can also * be used directly on annotation types as well. When applied, and if the annotation processor is applied for the builder-type * annotation then an implementation class is generated that supports the fluent-builder pattern for that type. *

@@ -29,4 +29,4 @@ *

  • Any static or default method will be ignored during APT processing.
  • * */ -package io.helidon.pico.builder; +package io.helidon.builder; diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/RequiredAttributeVisitor.java b/builder/builder/src/main/java/io/helidon/builder/spi/RequiredAttributeVisitor.java similarity index 89% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/RequiredAttributeVisitor.java rename to builder/builder/src/main/java/io/helidon/builder/spi/RequiredAttributeVisitor.java index 2a87b9958be..96d2a0e5c82 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/RequiredAttributeVisitor.java +++ b/builder/builder/src/main/java/io/helidon/builder/spi/RequiredAttributeVisitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.spi; +package io.helidon.builder.spi; import java.util.ArrayList; import java.util.List; @@ -22,16 +22,16 @@ import java.util.Objects; import java.util.function.Supplier; -import io.helidon.pico.builder.AttributeVisitor; +import io.helidon.builder.AttributeVisitor; /** * An implementation of {@link AttributeVisitor} that will validate each attribute to enforce not-null in accordance with * {@link io.helidon.config.metadata.ConfiguredOption#required()}. *

    - * Note that the source type having the {@link io.helidon.pico.builder.Builder} must be annotated with + * Note that the source type having the {@link io.helidon.builder.Builder} must be annotated with * {@code ConfiguredOption(required=true)} for this to be enforced. * Also note that this implementation will be used only when - * {@link io.helidon.pico.builder.Builder#requireLibraryDependencies()} is enabled. If not enabled then an implementation + * {@link io.helidon.builder.Builder#requireLibraryDependencies()} is enabled. If not enabled then an implementation * similar to this type will be inlined directly into the code-generated builder type. * * @deprecated This class is subject to change at any time - Helidon users should not use this directly. It will be referenced in diff --git a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/package-info.java b/builder/builder/src/main/java/io/helidon/builder/spi/package-info.java similarity index 94% rename from pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/package-info.java rename to builder/builder/src/main/java/io/helidon/builder/spi/package-info.java index 54451dc3e75..2f58fa53351 100644 --- a/pico/builder/builder/src/main/java/io/helidon/pico/builder/spi/package-info.java +++ b/builder/builder/src/main/java/io/helidon/builder/spi/package-info.java @@ -17,4 +17,4 @@ /** * Builder runtime tooling SPI. */ -package io.helidon.pico.builder.spi; +package io.helidon.builder.spi; diff --git a/pico/builder/builder/src/main/java/module-info.java b/builder/builder/src/main/java/module-info.java similarity index 80% rename from pico/builder/builder/src/main/java/module-info.java rename to builder/builder/src/main/java/module-info.java index 4488f9b61fa..6498d686e81 100644 --- a/pico/builder/builder/src/main/java/module-info.java +++ b/builder/builder/src/main/java/module-info.java @@ -15,9 +15,9 @@ */ /** - * The Pico Builder API / SPI module. + * The Builder API / SPI module. */ -module io.helidon.pico.builder { - exports io.helidon.pico.builder; - exports io.helidon.pico.builder.spi; +module io.helidon.builder { + exports io.helidon.builder; + exports io.helidon.builder.spi; } diff --git a/pico/builder/pom.xml b/builder/pom.xml similarity index 80% rename from pico/builder/pom.xml rename to builder/pom.xml index 9baea8f15fe..036f8d3526d 100644 --- a/pico/builder/pom.xml +++ b/builder/pom.xml @@ -23,21 +23,21 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - io.helidon.pico - helidon-pico-project + io.helidon + helidon-project 4.0.0-SNAPSHOT ../pom.xml 4.0.0 - io.helidon.pico.builder - helidon-pico-builder-project + io.helidon.builder + helidon-builder-project - Helidon Pico Builder Project + Helidon Builder Project pom - + 11 diff --git a/pico/builder/processor-spi/README.md b/builder/processor-spi/README.md similarity index 68% rename from pico/builder/processor-spi/README.md rename to builder/processor-spi/README.md index d80a9507970..9e8cee95681 100644 --- a/pico/builder/processor-spi/README.md +++ b/builder/processor-spi/README.md @@ -1,3 +1,3 @@ -# pico-builder-processor-spi +# builder-processor-spi This module should typically only be used during compile time diff --git a/pico/builder/processor-spi/pom.xml b/builder/processor-spi/pom.xml similarity index 77% rename from pico/builder/processor-spi/pom.xml rename to builder/processor-spi/pom.xml index 61c89c9b975..44893568702 100644 --- a/pico/builder/processor-spi/pom.xml +++ b/builder/processor-spi/pom.xml @@ -21,28 +21,29 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - io.helidon.pico.builder - helidon-pico-builder-project + io.helidon.builder + helidon-builder-project 4.0.0-SNAPSHOT ../pom.xml 4.0.0 - helidon-pico-builder-processor-spi - Helidon Pico Builder Processor SPI + helidon-builder-processor-spi + Helidon Builder Processor SPI io.helidon.common helidon-common + io.helidon.pico helidon-pico-types - io.helidon.pico.builder - helidon-pico-builder + io.helidon.builder + helidon-builder diff --git a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/BuilderCreator.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreator.java similarity index 89% rename from pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/BuilderCreator.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreator.java index 85da9abbe5e..520209c1eb7 100644 --- a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/BuilderCreator.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.spi; +package io.helidon.builder.processor.spi; import java.lang.annotation.Annotation; import java.util.List; @@ -23,7 +23,7 @@ import io.helidon.pico.types.AnnotationAndValue; /** - * Implementors of this contract will be called to process {@link io.helidon.pico.builder.BuilderTrigger}-annotated + * Implementors of this contract will be called to process {@link io.helidon.builder.BuilderTrigger}-annotated * annotation types that they know how to handle. This is based upon the {@link #supportedAnnotationTypes()} as well as the * {@link io.helidon.common.Weight} * assigned to the implementation class implementing this interface. @@ -31,8 +31,8 @@ public interface BuilderCreator { /** - * The set of {@link io.helidon.pico.builder.Builder}-like annotations that this creator knows how to handle. Note that - * this annotation must also be annotated with {@link io.helidon.pico.builder.BuilderTrigger} to qualify for inclusion. + * The set of {@link io.helidon.builder.Builder}-like annotations that this creator knows how to handle. Note that + * this annotation must also be annotated with {@link io.helidon.builder.BuilderTrigger} to qualify for inclusion. * This is akin to {@link javax.annotation.processing.Processor#getSupportedAnnotationTypes()}. * * @return Implementors should return the set of annotations they can handle diff --git a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/DefaultTypeAndBody.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/DefaultTypeAndBody.java similarity index 98% rename from pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/DefaultTypeAndBody.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/DefaultTypeAndBody.java index 4c4ec5e1130..da6b48a3335 100644 --- a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/DefaultTypeAndBody.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/DefaultTypeAndBody.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.spi; +package io.helidon.builder.processor.spi; import io.helidon.pico.types.TypeName; diff --git a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/DefaultTypeInfo.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/DefaultTypeInfo.java similarity index 99% rename from pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/DefaultTypeInfo.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/DefaultTypeInfo.java index 258e30a0f77..9dd65c6b32f 100644 --- a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/DefaultTypeInfo.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/DefaultTypeInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.spi; +package io.helidon.builder.processor.spi; import java.util.ArrayList; import java.util.Collection; diff --git a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeAndBody.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeAndBody.java similarity index 95% rename from pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeAndBody.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeAndBody.java index a9eb0ff0eee..699cf86e1b5 100644 --- a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeAndBody.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeAndBody.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.spi; +package io.helidon.builder.processor.spi; import io.helidon.pico.types.TypeName; diff --git a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeInfo.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfo.java similarity index 93% rename from pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeInfo.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfo.java index 3acc1e5c59f..e269c37874f 100644 --- a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeInfo.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.spi; +package io.helidon.builder.processor.spi; import java.util.List; import java.util.Optional; @@ -24,7 +24,7 @@ import io.helidon.pico.types.TypedElementName; /** - * Represents the model object for an interface type (e.g., one that was annotated with {@link io.helidon.pico.builder.Builder}). + * Represents the model object for an interface type (e.g., one that was annotated with {@link io.helidon.builder.Builder}). */ public interface TypeInfo { diff --git a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeInfoCreator.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreator.java similarity index 87% rename from pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeInfoCreator.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreator.java index 37ec0ea372d..5a04564b4f0 100644 --- a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/TypeInfoCreator.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.spi; +package io.helidon.builder.processor.spi; import java.util.Optional; @@ -25,12 +25,12 @@ import io.helidon.pico.types.TypeName; /** - * Used to create a {@link io.helidon.pico.builder.processor.spi.TypeInfo} from the provided arguments. + * Used to create a {@link TypeInfo} from the provided arguments. */ public interface TypeInfoCreator { /** - * Creates a {@link io.helidon.pico.builder.processor.spi.TypeInfo}. + * Creates a {@link TypeInfo}. * * @param annotation the annotation that triggered the creation * @param typeName the type name that is being processed that is annotated with the triggering annotation diff --git a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/package-info.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java similarity index 75% rename from pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/package-info.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java index 606c1d79656..7c569f5846b 100644 --- a/pico/builder/processor-spi/src/main/java/io/helidon/pico/builder/processor/spi/package-info.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java @@ -19,10 +19,10 @@ *

      *
    1. {@link io.helidon.pico.builder.processor.spi.BuilderCreator} - responsible for code generating the implementation w/ * a fluent builder.
    2. - *
    3. {@link io.helidon.pico.builder.processor.spi.TypeInfoCreator} - responsible for code generating the model object for + *
    4. {@link io.helidon.builder.processor.spi.TypeInfoCreator} - responsible for code generating the model object for * the target interface.
    5. - *
    6. {@link io.helidon.pico.builder.processor.spi.TypeAndBody} - the dom-like description of the target type of the + *
    7. {@link io.helidon.builder.processor.spi.TypeAndBody} - the dom-like description of the target type of the * builder.
    8. *
    */ -package io.helidon.pico.builder.processor.spi; +package io.helidon.builder.processor.spi; diff --git a/pico/builder/processor-spi/src/main/java/module-info.java b/builder/processor-spi/src/main/java/module-info.java similarity index 79% rename from pico/builder/processor-spi/src/main/java/module-info.java rename to builder/processor-spi/src/main/java/module-info.java index 2eafd7ce6a3..71e34822b14 100644 --- a/pico/builder/processor-spi/src/main/java/module-info.java +++ b/builder/processor-spi/src/main/java/module-info.java @@ -15,13 +15,13 @@ */ /** - * The Helidon Pico Builder Processor SPI module. + * The Helidon Builder Processor SPI module. */ -module io.helidon.pico.builder.processor.spi { +module io.helidon.builder.processor.spi { requires java.compiler; - requires io.helidon.pico.builder; + requires io.helidon.builder; requires io.helidon.pico.types; requires io.helidon.common; - exports io.helidon.pico.builder.processor.spi; + exports io.helidon.builder.processor.spi; } diff --git a/pico/builder/processor-tools/README.md b/builder/processor-tools/README.md similarity index 75% rename from pico/builder/processor-tools/README.md rename to builder/processor-tools/README.md index c92a6f42762..f1241a09ca7 100644 --- a/pico/builder/processor-tools/README.md +++ b/builder/processor-tools/README.md @@ -1,3 +1,3 @@ -# pico-builder-tools +# builder-tools This module should typically only be used during compile time. diff --git a/pico/builder/processor-tools/pom.xml b/builder/processor-tools/pom.xml similarity index 82% rename from pico/builder/processor-tools/pom.xml rename to builder/processor-tools/pom.xml index eb075bc8242..91cbc6d8a02 100644 --- a/pico/builder/processor-tools/pom.xml +++ b/builder/processor-tools/pom.xml @@ -21,24 +21,24 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - io.helidon.pico.builder - helidon-pico-builder-project + io.helidon.builder + helidon-builder-project 4.0.0-SNAPSHOT ../pom.xml 4.0.0 - helidon-pico-builder-processor-tools - Helidon Pico Builder Processor Tools + helidon-builder-processor-tools + Helidon Builder Processor Tools - io.helidon.pico.builder - helidon-pico-builder + io.helidon.builder + helidon-builder - io.helidon.pico.builder - helidon-pico-builder-processor-spi + io.helidon.builder + helidon-builder-processor-spi io.helidon.pico diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BeanUtils.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BeanUtils.java similarity index 99% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BeanUtils.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BeanUtils.java index f8fcb560ea3..36a94a657c3 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BeanUtils.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BeanUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import java.util.Collections; import java.util.List; diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java similarity index 92% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java index 5fcc2c02857..7c279ebe57c 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BodyContext.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import java.util.ArrayList; import java.util.Collections; @@ -25,20 +25,20 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; -import io.helidon.pico.builder.processor.spi.TypeInfo; +import io.helidon.builder.processor.spi.TypeInfo; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; import io.helidon.pico.types.TypeName; import io.helidon.pico.types.TypedElementName; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.BUILDER_ANNO_TYPE_NAME; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.DEFAULT_INCLUDE_META_ATTRIBUTES; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.DEFAULT_LIST_TYPE; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.DEFAULT_MAP_TYPE; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.DEFAULT_SET_TYPE; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.SUPPORT_STREAMS_ON_BUILDER; -import static io.helidon.pico.builder.processor.tools.DefaultBuilderCreator.SUPPORT_STREAMS_ON_IMPL; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.BUILDER_ANNO_TYPE_NAME; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_INCLUDE_META_ATTRIBUTES; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_LIST_TYPE; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_MAP_TYPE; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_SET_TYPE; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.SUPPORT_STREAMS_ON_BUILDER; +import static io.helidon.builder.processor.tools.DefaultBuilderCreator.SUPPORT_STREAMS_ON_IMPL; /** * Represents the context of the body being code generated. @@ -333,7 +333,7 @@ private static boolean hasStreamSupportOnBuilder(boolean ignoreDoingConcreteClas } /** - * In support of {@link io.helidon.pico.builder.Builder#includeMetaAttributes()}. + * In support of {@link io.helidon.builder.Builder#includeMetaAttributes()}. */ private static boolean toIncludeMetaAttributes(AnnotationAndValue builderAnnotation, TypeInfo typeInfo) { @@ -342,7 +342,7 @@ private static boolean toIncludeMetaAttributes(AnnotationAndValue builderAnnotat } /** - * In support of {@link io.helidon.pico.builder.Builder#requireLibraryDependencies()}. + * In support of {@link io.helidon.builder.Builder#requireLibraryDependencies()}. */ private static boolean toRequireLibraryDependencies(AnnotationAndValue builderAnnotation, TypeInfo typeInfo) { @@ -351,7 +351,7 @@ private static boolean toRequireLibraryDependencies(AnnotationAndValue builderAn } /** - * In support of {@link io.helidon.pico.builder.Builder#requireBeanStyle()}. + * In support of {@link io.helidon.builder.Builder#requireBeanStyle()}. */ private static boolean toRequireBeanStyle(AnnotationAndValue builderAnnotation, TypeInfo typeInfo) { @@ -360,7 +360,7 @@ private static boolean toRequireBeanStyle(AnnotationAndValue builderAnnotation, } /** - * In support of {@link io.helidon.pico.builder.Builder#listImplType()}. + * In support of {@link io.helidon.builder.Builder#listImplType()}. */ private static String toListImplType(AnnotationAndValue builderAnnotation, TypeInfo typeInfo) { @@ -369,7 +369,7 @@ private static String toListImplType(AnnotationAndValue builderAnnotation, } /** - * In support of {@link io.helidon.pico.builder.Builder#mapImplType()} ()}. + * In support of {@link io.helidon.builder.Builder#mapImplType()} ()}. */ private static String toMapImplType(AnnotationAndValue builderAnnotation, TypeInfo typeInfo) { @@ -378,7 +378,7 @@ private static String toMapImplType(AnnotationAndValue builderAnnotation, } /** - * In support of {@link io.helidon.pico.builder.Builder#setImplType()}. + * In support of {@link io.helidon.builder.Builder#setImplType()}. */ private static String toSetImplType(AnnotationAndValue builderAnnotation, TypeInfo typeInfo) { diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BuilderTemplateHelper.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTemplateHelper.java similarity index 96% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BuilderTemplateHelper.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTemplateHelper.java index f5f9017814c..bdb9ccc4a6b 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BuilderTemplateHelper.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTemplateHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; class BuilderTemplateHelper { diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BuilderTypeTools.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java similarity index 97% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BuilderTypeTools.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java index 9b28b8ebcb1..b6382682473 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/BuilderTypeTools.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -46,9 +46,9 @@ import io.helidon.common.Weight; import io.helidon.common.Weighted; -import io.helidon.pico.builder.processor.spi.DefaultTypeInfo; -import io.helidon.pico.builder.processor.spi.TypeInfo; -import io.helidon.pico.builder.processor.spi.TypeInfoCreator; +import io.helidon.builder.processor.spi.DefaultTypeInfo; +import io.helidon.builder.processor.spi.TypeInfo; +import io.helidon.builder.processor.spi.TypeInfoCreator; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; import io.helidon.pico.types.DefaultTypeName; @@ -57,7 +57,7 @@ import io.helidon.pico.types.TypedElementName; /** - * The default implementation for {@link io.helidon.pico.builder.processor.spi.TypeInfoCreator}. This also contains an abundance of other + * The default implementation for {@link io.helidon.builder.processor.spi.TypeInfoCreator}. This also contains an abundance of other * useful methods used for annotation processing. */ @Weight(Weighted.DEFAULT_WEIGHT - 1) diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java similarity index 98% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java index a8619701068..09f744acf22 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/DefaultBuilderCreator.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -30,26 +30,26 @@ import java.util.function.Function; import java.util.stream.Collectors; +import io.helidon.builder.Annotated; +import io.helidon.builder.AttributeVisitor; +import io.helidon.builder.Builder; +import io.helidon.builder.Singular; +import io.helidon.builder.processor.spi.BuilderCreator; +import io.helidon.builder.processor.spi.DefaultTypeAndBody; +import io.helidon.builder.processor.spi.TypeAndBody; +import io.helidon.builder.processor.spi.TypeInfo; +import io.helidon.builder.spi.RequiredAttributeVisitor; import io.helidon.common.Weight; import io.helidon.common.Weighted; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Annotated; -import io.helidon.pico.builder.AttributeVisitor; -import io.helidon.pico.builder.Builder; -import io.helidon.pico.builder.Singular; -import io.helidon.pico.builder.processor.spi.BuilderCreator; -import io.helidon.pico.builder.processor.spi.DefaultTypeAndBody; -import io.helidon.pico.builder.processor.spi.TypeAndBody; -import io.helidon.pico.builder.processor.spi.TypeInfo; -import io.helidon.pico.builder.spi.RequiredAttributeVisitor; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; import io.helidon.pico.types.DefaultTypeName; import io.helidon.pico.types.TypeName; import io.helidon.pico.types.TypedElementName; -import static io.helidon.pico.builder.processor.tools.BodyContext.TAG_META_PROPS; -import static io.helidon.pico.builder.processor.tools.BodyContext.toBeanAttributeName; +import static io.helidon.builder.processor.tools.BodyContext.TAG_META_PROPS; +import static io.helidon.builder.processor.tools.BodyContext.toBeanAttributeName; /** * Default implementation for {@link io.helidon.pico.builder.processor.spi.BuilderCreator}. @@ -813,7 +813,7 @@ protected void appendDirectNonOptionalSetter(StringBuilder builder, } /** - * Append {@link io.helidon.pico.builder.Annotated} annotations if any. + * Append {@link Annotated} annotations if any. * * @param builder the builder * @param annotations the list of annotations @@ -978,7 +978,7 @@ private static char[] reverseBeanName(String beanName) { } /** - * In support of {@link io.helidon.pico.builder.Builder#packageName()}. + * In support of {@link io.helidon.builder.Builder#packageName()}. */ private String toPackageName(String packageName, AnnotationAndValue builderAnnotation) { @@ -993,21 +993,21 @@ private String toPackageName(String packageName, } /** - * In support of {@link io.helidon.pico.builder.Builder#abstractImplPrefix()}. + * In support of {@link io.helidon.builder.Builder#abstractImplPrefix()}. */ private String toAbstractImplTypePrefix(AnnotationAndValue builderAnnotation) { return builderAnnotation.value("abstractImplPrefix").orElse(DEFAULT_ABSTRACT_IMPL_PREFIX); } /** - * In support of {@link io.helidon.pico.builder.Builder#implPrefix()}. + * In support of {@link io.helidon.builder.Builder#implPrefix()}. */ private String toImplTypePrefix(AnnotationAndValue builderAnnotation) { return builderAnnotation.value("implPrefix").orElse(DEFAULT_IMPL_PREFIX); } /** - * In support of {@link io.helidon.pico.builder.Builder#implSuffix()}. + * In support of {@link io.helidon.builder.Builder#implSuffix()}. */ private String toImplTypeSuffix(AnnotationAndValue builderAnnotation) { return builderAnnotation.value("implSuffix").orElse(DEFAULT_SUFFIX); diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateJavadoc.java similarity index 99% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateJavadoc.java index e8cc9e99d23..2168b8535ed 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateJavadoc.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateJavadoc.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import io.helidon.pico.types.TypedElementName; diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateMethod.java similarity index 99% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateMethod.java index 89c5cd247f8..cb3d72a8654 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateMethod.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateMethod.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import java.util.List; import java.util.Optional; diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java similarity index 99% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java index 80bf74a439f..0dd14e5f42d 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/GenerateVisitorSupport.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; final class GenerateVisitorSupport { private GenerateVisitorSupport() { diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/ToStringAnnotationValueVisitor.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/ToStringAnnotationValueVisitor.java similarity index 99% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/ToStringAnnotationValueVisitor.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/ToStringAnnotationValueVisitor.java index 18ece5cdc10..336a5882707 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/ToStringAnnotationValueVisitor.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/ToStringAnnotationValueVisitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import java.util.ArrayList; import java.util.List; diff --git a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/package-info.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/package-info.java similarity index 94% rename from pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/package-info.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/package-info.java index 4fbbd97b966..67c2fd93fea 100644 --- a/pico/builder/processor-tools/src/main/java/io/helidon/pico/builder/processor/tools/package-info.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/package-info.java @@ -18,4 +18,4 @@ * The Helidon Pico Builder Processor Tools package. These are generally only needed by other Helidon modules like the Builder * annotation processor, etc. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; diff --git a/pico/builder/processor-tools/src/main/java/module-info.java b/builder/processor-tools/src/main/java/module-info.java similarity index 59% rename from pico/builder/processor-tools/src/main/java/module-info.java rename to builder/processor-tools/src/main/java/module-info.java index b8c9a9a1f67..14b7be124cf 100644 --- a/pico/builder/processor-tools/src/main/java/module-info.java +++ b/builder/processor-tools/src/main/java/module-info.java @@ -15,20 +15,20 @@ */ /** - * The Pico Builder Processor Tools module. + * The Builder Processor Tools module. */ -module io.helidon.pico.builder.processor.tools { +module io.helidon.builder.processor.tools { requires java.compiler; requires io.helidon.pico.types; - requires io.helidon.pico.builder; - requires io.helidon.pico.builder.processor.spi; + requires io.helidon.builder; + requires io.helidon.builder.processor.spi; requires io.helidon.common; requires io.helidon.config.metadata; - exports io.helidon.pico.builder.processor.tools; + exports io.helidon.builder.processor.tools; - provides io.helidon.pico.builder.processor.spi.BuilderCreator - with io.helidon.pico.builder.processor.tools.DefaultBuilderCreator; - provides io.helidon.pico.builder.processor.spi.TypeInfoCreator - with io.helidon.pico.builder.processor.tools.BuilderTypeTools; + provides io.helidon.builder.processor.spi.BuilderCreator + with io.helidon.builder.processor.tools.DefaultBuilderCreator; + provides io.helidon.builder.processor.spi.TypeInfoCreator + with io.helidon.builder.processor.tools.BuilderTypeTools; } diff --git a/pico/builder/processor-tools/src/test/java/io/helidon/pico/builder/processor/tools/BeanUtilsTest.java b/builder/processor-tools/src/test/java/io/helidon/builder/processor/tools/BeanUtilsTest.java similarity index 96% rename from pico/builder/processor-tools/src/test/java/io/helidon/pico/builder/processor/tools/BeanUtilsTest.java rename to builder/processor-tools/src/test/java/io/helidon/builder/processor/tools/BeanUtilsTest.java index e792c8f8c6a..66128c96dfa 100644 --- a/pico/builder/processor-tools/src/test/java/io/helidon/pico/builder/processor/tools/BeanUtilsTest.java +++ b/builder/processor-tools/src/test/java/io/helidon/builder/processor/tools/BeanUtilsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor.tools; +package io.helidon.builder.processor.tools; import java.util.Collection; import java.util.List; @@ -30,9 +30,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static io.helidon.pico.builder.processor.tools.BeanUtils.isBooleanType; -import static io.helidon.pico.builder.processor.tools.BeanUtils.isValidMethodType; -import static io.helidon.pico.builder.processor.tools.BeanUtils.validateAndParseMethodName; +import static io.helidon.builder.processor.tools.BeanUtils.isBooleanType; +import static io.helidon.builder.processor.tools.BeanUtils.isValidMethodType; +import static io.helidon.builder.processor.tools.BeanUtils.validateAndParseMethodName; import static org.hamcrest.MatcherAssert.assertThat; class BeanUtilsTest { diff --git a/pico/builder/processor/pom.xml b/builder/processor/pom.xml similarity index 78% rename from pico/builder/processor/pom.xml rename to builder/processor/pom.xml index 90e71386602..67816c55df6 100644 --- a/pico/builder/processor/pom.xml +++ b/builder/processor/pom.xml @@ -21,15 +21,15 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - io.helidon.pico.builder - helidon-pico-builder-project + io.helidon.builder + helidon-builder-project 4.0.0-SNAPSHOT ../pom.xml 4.0.0 - helidon-pico-builder-processor - Helidon Pico Builder Annotation Processor + helidon-builder-processor + Helidon Builder Annotation Processor @@ -37,12 +37,12 @@ helidon-common - io.helidon.pico.builder - helidon-pico-builder + io.helidon.builder + helidon-builder - io.helidon.pico.builder - helidon-pico-builder-processor-tools + io.helidon.builder + helidon-builder-processor-tools diff --git a/pico/builder/processor/src/main/java/io/helidon/pico/builder/processor/BuilderProcessor.java b/builder/processor/src/main/java/io/helidon/builder/processor/BuilderProcessor.java similarity index 95% rename from pico/builder/processor/src/main/java/io/helidon/pico/builder/processor/BuilderProcessor.java rename to builder/processor/src/main/java/io/helidon/builder/processor/BuilderProcessor.java index 8b4010360f4..4905d95d4d9 100644 --- a/pico/builder/processor/src/main/java/io/helidon/pico/builder/processor/BuilderProcessor.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/BuilderProcessor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.processor; +package io.helidon.builder.processor; import java.io.IOException; import java.io.Writer; @@ -41,17 +41,17 @@ import io.helidon.common.HelidonServiceLoader; import io.helidon.common.Weights; -import io.helidon.pico.builder.processor.spi.BuilderCreator; -import io.helidon.pico.builder.processor.spi.TypeAndBody; -import io.helidon.pico.builder.processor.spi.TypeInfo; -import io.helidon.pico.builder.processor.spi.TypeInfoCreator; -import io.helidon.pico.builder.processor.tools.BuilderTypeTools; +import io.helidon.builder.processor.spi.BuilderCreator; +import io.helidon.builder.processor.spi.TypeAndBody; +import io.helidon.builder.processor.spi.TypeInfo; +import io.helidon.builder.processor.spi.TypeInfoCreator; +import io.helidon.builder.processor.tools.BuilderTypeTools; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultTypeName; import io.helidon.pico.types.TypeName; /** - * The processor for handling any annotation having a {@link io.helidon.pico.builder.BuilderTrigger}. + * The processor for handling any annotation having a {@link io.helidon.builder.BuilderTrigger}. */ public class BuilderProcessor extends AbstractProcessor { private static final System.Logger LOGGER = System.getLogger(BuilderProcessor.class.getName()); diff --git a/pico/builder/processor/src/main/java/io/helidon/pico/builder/processor/package-info.java b/builder/processor/src/main/java/io/helidon/builder/processor/package-info.java similarity index 86% rename from pico/builder/processor/src/main/java/io/helidon/pico/builder/processor/package-info.java rename to builder/processor/src/main/java/io/helidon/builder/processor/package-info.java index e9cd8862dc1..cb280d178a7 100644 --- a/pico/builder/processor/src/main/java/io/helidon/pico/builder/processor/package-info.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/package-info.java @@ -15,6 +15,6 @@ */ /** - * The Pico Builder annotation processing package. + * The Builder annotation processing package. */ -package io.helidon.pico.builder.processor; +package io.helidon.builder.processor; diff --git a/pico/builder/processor/src/main/java/module-info.java b/builder/processor/src/main/java/module-info.java similarity index 58% rename from pico/builder/processor/src/main/java/module-info.java rename to builder/processor/src/main/java/module-info.java index 7bf5c9db3ae..e1b0e329bd7 100644 --- a/pico/builder/processor/src/main/java/module-info.java +++ b/builder/processor/src/main/java/module-info.java @@ -15,20 +15,21 @@ */ /** - * The Pico Builder annotation processor module. + * The Builder annotation processor module. */ -module io.helidon.pico.builder.processor { +module io.helidon.builder.processor { requires java.compiler; requires io.helidon.common; - requires io.helidon.pico.builder; - requires io.helidon.pico.builder.processor.spi; - requires io.helidon.pico.builder.processor.tools; + requires io.helidon.builder; + requires io.helidon.builder.processor.spi; + requires io.helidon.builder.processor.tools; requires io.helidon.pico.types; - exports io.helidon.pico.builder.processor; + exports io.helidon.builder.processor; - provides javax.annotation.processing.Processor with io.helidon.pico.builder.processor.BuilderProcessor; + provides javax.annotation.processing.Processor + with io.helidon.builder.processor.BuilderProcessor; - uses io.helidon.pico.builder.processor.spi.BuilderCreator; - uses io.helidon.pico.builder.processor.spi.TypeInfoCreator; + uses io.helidon.builder.processor.spi.BuilderCreator; + uses io.helidon.builder.processor.spi.TypeInfoCreator; } diff --git a/pico/builder/tests/builder/pom.xml b/builder/tests/builder/pom.xml similarity index 81% rename from pico/builder/tests/builder/pom.xml rename to builder/tests/builder/pom.xml index d19a71fbbbd..9444fa1709d 100644 --- a/pico/builder/tests/builder/pom.xml +++ b/builder/tests/builder/pom.xml @@ -21,15 +21,15 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - io.helidon.pico.builder.tests - helidon-pico-builder-tests-project + io.helidon.builder.tests + helidon-builder-tests-project 4.0.0-SNAPSHOT ../pom.xml 4.0.0 - helidon-pico-builder-test-builder - Helidon Pico Builder Tests + helidon-builder-test-builder + Helidon Builder Tests true @@ -41,17 +41,13 @@ - io.helidon.pico.builder - helidon-pico-builder-processor + io.helidon.builder + helidon-builder-processor provided - io.helidon.pico.builder - helidon-pico-builder - - - io.helidon.pico.builder.config - helidon-pico-builder-config + io.helidon.builder + helidon-builder io.helidon.config @@ -99,8 +95,8 @@ true - io.helidon.pico.builder - helidon-pico-builder-processor + io.helidon.builder + helidon-builder-processor ${helidon.version} diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/A.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/A.java similarity index 89% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/A.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/A.java index f94211a65a6..a0ba102d6d3 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/A.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/A.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Example A. diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/AnnotationCase.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCase.java similarity index 91% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/AnnotationCase.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCase.java index ea9e409807e..53042f1e457 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/AnnotationCase.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCase.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; /** * Demonstrates how an annotation can be extended, and then used as the basis for a builder. * - * @see io.helidon.pico.builder.test.testsubjects.AnnotationCaseExt + * @see AnnotationCaseExt */ public @interface AnnotationCase { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/AnnotationCaseExt.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCaseExt.java similarity index 89% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/AnnotationCaseExt.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCaseExt.java index faaf761d67e..06dd140d714 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/AnnotationCaseExt.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCaseExt.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Extends the annotation so that a builder can be built for it. diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/B.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/B.java similarity index 89% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/B.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/B.java index ff62595c888..2eb8208c64a 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/B.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/B.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Example B extending A. diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/C.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/C.java similarity index 89% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/C.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/C.java index c23bdafa8ba..a282d25a409 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/C.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/C.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Example C extending B. diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ChildInterfaceIsABuilder.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ChildInterfaceIsABuilder.java similarity index 95% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ChildInterfaceIsABuilder.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ChildInterfaceIsABuilder.java index 7191b9ec576..8de56a00a8e 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ChildInterfaceIsABuilder.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ChildInterfaceIsABuilder.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Optional; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Demonstrates builder usages when the parent in a plain old interface (and not a target of the builder annotation), while this diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ComplexCase.java similarity index 92% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ComplexCase.java index 7d0bba9b188..867a7f1e683 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ComplexCase.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ComplexCase.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.List; import java.util.Map; import java.util.Set; -import io.helidon.pico.builder.Builder; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Builder; +import io.helidon.builder.Singular; /** * Used for demonstrating and testing the Pico Builder. @@ -31,7 +31,7 @@ public interface ComplexCase extends MyConfigBean { /** - * Used for testing, and demonstrating the {@link io.helidon.pico.builder.Singular} annotation. + * Used for testing, and demonstrating the {@link io.helidon.builder.Singular} annotation. * * @return ignored, here for testing purposes only */ @@ -39,7 +39,7 @@ public interface ComplexCase extends MyConfigBean { Map> getMapOfKeyToConfigBeans(); /** - * Used for testing, and demonstrating the {@link io.helidon.pico.builder.Singular} annotation. + * Used for testing, and demonstrating the {@link io.helidon.builder.Singular} annotation. * * @return ignored, here for testing purposes only */ diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Container.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Container.java similarity index 88% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Container.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Container.java index 6a08ee37dfb..9deeab1613c 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Container.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Container.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Optional; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** - * Base for {@link io.helidon.pico.builder.test.testsubjects.PickleBarrel}. + * Base for {@link PickleBarrel}. */ @Builder public interface Container { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/CustomNamed.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/CustomNamed.java similarity index 92% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/CustomNamed.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/CustomNamed.java index 31a1929f280..c9a5285c494 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/CustomNamed.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/CustomNamed.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.LinkedList; import java.util.List; @@ -23,9 +23,9 @@ import java.util.TreeMap; import java.util.TreeSet; -import io.helidon.pico.builder.Annotated; -import io.helidon.pico.builder.Builder; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Annotated; +import io.helidon.builder.Builder; +import io.helidon.builder.Singular; /** * Used for demonstrating and testing the Pico Builder. diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/EdgeCases.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/EdgeCases.java similarity index 93% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/EdgeCases.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/EdgeCases.java index ab02386d5e5..fc62b50b6bd 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/EdgeCases.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/EdgeCases.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Optional; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Used for demonstrating and testing the Pico Builder. diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level0.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level0.java similarity index 88% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level0.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level0.java index 396c0800611..902012a050c 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level0.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level0.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Demonstrates multi-level inheritance for the generated builder. * - * @see io.helidon.pico.builder.test.testsubjects.Level1 + * @see Level1 */ @Builder(requireLibraryDependencies = false, requireBeanStyle = true, implPrefix = "", implSuffix = "Impl") public interface Level0 { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level1.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level1.java similarity index 93% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level1.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level1.java index c4c3518d990..6aae70ca344 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level1.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level1.java @@ -14,17 +14,17 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Optional; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Demonstrates multi-level inheritance for the generated builder. * - * @see io.helidon.pico.builder.test.testsubjects.Level2 + * @see Level2 */ @Builder(requireLibraryDependencies = false, requireBeanStyle = true, implPrefix = "", implSuffix = "Impl") public interface Level1 extends Level0 { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level2.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level2.java similarity index 89% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level2.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level2.java index 6386095f3cb..17e53402a6a 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Level2.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Level2.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.List; import java.util.Map; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Builder; +import io.helidon.builder.Singular; /** * Demonstrates multi-level inheritance for the generated builder. @@ -39,7 +39,7 @@ public interface Level2 extends Level1 { String getLevel0StringAttribute(); /** - * Used for testing and demonstrating the use of {@link io.helidon.pico.builder.Singular}. + * Used for testing and demonstrating the use of {@link io.helidon.builder.Singular}. * * @return ignored, here for testing purposes only */ @@ -47,7 +47,7 @@ public interface Level2 extends Level1 { List getLevel2Level0Info(); /** - * Used for testing and demonstrating the use of {@link io.helidon.pico.builder.Singular}. + * Used for testing and demonstrating the use of {@link io.helidon.builder.Singular}. * * @return ignored, here for testing purposes only */ @@ -55,7 +55,7 @@ public interface Level2 extends Level1 { List getLevel2ListOfLevel0s(); /** - * Used for testing and demonstrating the use of {@link io.helidon.pico.builder.Singular}. + * Used for testing and demonstrating the use of {@link io.helidon.builder.Singular}. * * @return ignored, here for testing purposes only */ diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/MyConfigBean.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/MyConfigBean.java similarity index 91% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/MyConfigBean.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/MyConfigBean.java index edfe0ea2b5a..c47df8d907e 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/MyConfigBean.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/MyConfigBean.java @@ -14,16 +14,16 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import io.helidon.config.metadata.ConfiguredOption; import io.helidon.config.metadata.ConfiguredValue; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Used for demonstrating and testing the Pico Builder. * - * @see io.helidon.pico.builder.test.testsubjects.MyDerivedConfigBean + * @see MyDerivedConfigBean */ @Builder(requireLibraryDependencies = false, requireBeanStyle = true, implPrefix = "", implSuffix = "Impl") public interface MyConfigBean { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/MyDerivedConfigBean.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/MyDerivedConfigBean.java similarity index 86% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/MyDerivedConfigBean.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/MyDerivedConfigBean.java index d5372ccbaae..d4572021604 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/MyDerivedConfigBean.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/MyDerivedConfigBean.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Used for demonstrating and testing the Pico Builder. * - * @see io.helidon.pico.builder.test.testsubjects.MyConfigBean + * @see MyConfigBean */ @Builder(requireLibraryDependencies = false, requireBeanStyle = true, implPrefix = "", implSuffix = "Impl") public interface MyDerivedConfigBean extends MyConfigBean { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ParentInterfaceNotABuilder.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ParentInterfaceNotABuilder.java similarity index 92% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ParentInterfaceNotABuilder.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ParentInterfaceNotABuilder.java index fed89f82d90..995eae4bf97 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ParentInterfaceNotABuilder.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ParentInterfaceNotABuilder.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Optional; /** * Used for demonstrating (and testing) multi-inheritance of interfaces and the builders that are produced. * - * @see io.helidon.pico.builder.test.testsubjects.ChildInterfaceIsABuilder + * @see ChildInterfaceIsABuilder */ public interface ParentInterfaceNotABuilder extends ParentOfParentInterfaceIsABuilder { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ParentOfParentInterfaceIsABuilder.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ParentOfParentInterfaceIsABuilder.java similarity index 87% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ParentOfParentInterfaceIsABuilder.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ParentOfParentInterfaceIsABuilder.java index b4402a7f680..8ec3b4cfe17 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/ParentOfParentInterfaceIsABuilder.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/ParentOfParentInterfaceIsABuilder.java @@ -14,17 +14,17 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.net.URI; import java.util.Optional; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Used for demonstrating (and testing) multi-inheritance of interfaces and the builders that are produced. * - * @see io.helidon.pico.builder.test.testsubjects.ParentInterfaceNotABuilder + * @see ParentInterfaceNotABuilder */ @Builder(implPrefix = "", implSuffix = "Impl") public interface ParentOfParentInterfaceIsABuilder { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Pickle.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Pickle.java similarity index 91% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Pickle.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Pickle.java index 68186ce92af..2c4b3c32e68 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/Pickle.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/Pickle.java @@ -14,17 +14,17 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Optional; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * A pickle. Demonstrates the use of enumerated types, optionals, and validation on builders. * - * @see io.helidon.pico.builder.test.testsubjects.PickleBarrel + * @see PickleBarrel */ @Builder public interface Pickle { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/PickleBarrel.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/PickleBarrel.java similarity index 85% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/PickleBarrel.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/PickleBarrel.java index 910851ef8f0..6fea8a0aadc 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/PickleBarrel.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/PickleBarrel.java @@ -14,17 +14,17 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.List; -import io.helidon.pico.builder.Builder; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Builder; +import io.helidon.builder.Singular; /** * Demonstrates the builder using the singular pattern, enumerated types, and validation of required attributes. * - * @see io.helidon.pico.builder.test.testsubjects.Container + * @see Container */ @Builder // this will trigger the creation of DefaultPickleBarrel.java under target/generated-sources/annotations/. public interface PickleBarrel extends Container { diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/T.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/T.java similarity index 89% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/T.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/T.java index 2df415111c8..546a579fad0 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/T.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/T.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Example T extending B. diff --git a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/package-info.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java similarity index 92% rename from pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/package-info.java rename to builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java index a90890705e8..245b94dfffb 100644 --- a/pico/builder/tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/package-info.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java @@ -17,4 +17,4 @@ /** * Test subjects for the Pico Builder. */ -package io.helidon.pico.builder.test.testsubjects; +package io.helidon.builder.test.testsubjects; diff --git a/pico/builder/tests/builder/src/main/java/module-info.java b/builder/tests/builder/src/main/java/module-info.java similarity index 87% rename from pico/builder/tests/builder/src/main/java/module-info.java rename to builder/tests/builder/src/main/java/module-info.java index 23b72f8123d..dec300d64ae 100644 --- a/pico/builder/tests/builder/src/main/java/module-info.java +++ b/builder/tests/builder/src/main/java/module-info.java @@ -15,12 +15,12 @@ */ /** - * Pico Builder Test module. + * Helidon Builder Test module. */ -module io.helidon.pico.builder.test.builder { +module io.helidon.builder.test.builder { requires static com.fasterxml.jackson.annotation; requires static io.helidon.config.metadata; requires io.helidon.common; - requires io.helidon.pico.builder; + requires io.helidon.builder; } diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/AnnotationCaseTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/AnnotationCaseTest.java similarity index 87% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/AnnotationCaseTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/AnnotationCaseTest.java index 7e27c100abf..b56b56813bf 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/AnnotationCaseTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/AnnotationCaseTest.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; import java.util.Arrays; -import io.helidon.pico.builder.test.testsubjects.AnnotationCase; -import io.helidon.pico.builder.test.testsubjects.DefaultAnnotationCaseExt; +import io.helidon.builder.test.testsubjects.AnnotationCase; +import io.helidon.builder.test.testsubjects.DefaultAnnotationCaseExt; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/ComplexCaseTest.java similarity index 90% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/ComplexCaseTest.java index 168e458cfac..448d3c71340 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ComplexCaseTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/ComplexCaseTest.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import io.helidon.pico.builder.test.testsubjects.ComplexCaseImpl; -import io.helidon.pico.builder.test.testsubjects.MyConfigBean; +import io.helidon.builder.test.testsubjects.ComplexCaseImpl; +import io.helidon.builder.test.testsubjects.MyConfigBean; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/CustomNamedTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/CustomNamedTest.java similarity index 92% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/CustomNamedTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/CustomNamedTest.java index 792c89501ee..90e1c0df177 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/CustomNamedTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/CustomNamedTest.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; -import io.helidon.pico.builder.test.testsubjects.CustomNamed; -import io.helidon.pico.builder.test.testsubjects.impl.DefaultCustomNamed; +import io.helidon.builder.test.testsubjects.CustomNamed; +import io.helidon.builder.test.testsubjects.impl.DefaultCustomNamed; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.MapperFeature; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/DependsOnAllBuilderTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/DependsOnAllBuilderTest.java similarity index 96% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/DependsOnAllBuilderTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/DependsOnAllBuilderTest.java index 985edc2307e..0a3414aeb31 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/DependsOnAllBuilderTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/DependsOnAllBuilderTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/DependsOnAllBuilders.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/DependsOnAllBuilders.java similarity index 69% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/DependsOnAllBuilders.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/DependsOnAllBuilders.java index c41a069850d..89286fd09b5 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/DependsOnAllBuilders.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/DependsOnAllBuilders.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; -import io.helidon.pico.builder.test.testsubjects.CustomNamed; -import io.helidon.pico.builder.test.testsubjects.Level2; -import io.helidon.pico.builder.test.testsubjects.Level2Impl; -import io.helidon.pico.builder.test.testsubjects.MyConfigBean; -import io.helidon.pico.builder.test.testsubjects.MyConfigBeanImpl; -import io.helidon.pico.builder.test.testsubjects.impl.DefaultCustomNamed; +import io.helidon.builder.test.testsubjects.CustomNamed; +import io.helidon.builder.test.testsubjects.Level2; +import io.helidon.builder.test.testsubjects.Level2Impl; +import io.helidon.builder.test.testsubjects.MyConfigBean; +import io.helidon.builder.test.testsubjects.MyConfigBeanImpl; +import io.helidon.builder.test.testsubjects.impl.DefaultCustomNamed; class DependsOnAllBuilders { diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/EdgeCasesTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/EdgeCasesTest.java similarity index 92% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/EdgeCasesTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/EdgeCasesTest.java index de91e7d2031..34af5acce2a 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/EdgeCasesTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/EdgeCasesTest.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; -import io.helidon.pico.builder.test.testsubjects.DefaultEdgeCases; +import io.helidon.builder.test.testsubjects.DefaultEdgeCases; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/LevelTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/LevelTest.java similarity index 92% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/LevelTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/LevelTest.java index e876a848dc6..cdb1fa061f5 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/LevelTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/LevelTest.java @@ -14,20 +14,20 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; import java.util.Collections; import java.util.function.Supplier; -import io.helidon.pico.builder.test.testsubjects.Level0; -import io.helidon.pico.builder.test.testsubjects.Level0Impl; -import io.helidon.pico.builder.api.test.testsubjects.Level0ManualImpl; -import io.helidon.pico.builder.test.testsubjects.Level1; -import io.helidon.pico.builder.test.testsubjects.Level1Impl; -import io.helidon.pico.builder.api.test.testsubjects.Level1ManualImpl; -import io.helidon.pico.builder.test.testsubjects.Level2; -import io.helidon.pico.builder.test.testsubjects.Level2Impl; -import io.helidon.pico.builder.api.test.testsubjects.Level2ManualImpl; +import io.helidon.builder.test.testsubjects.Level0; +import io.helidon.builder.test.testsubjects.Level0Impl; +import io.helidon.builder.test.testsubjects.Level0ManualImpl; +import io.helidon.builder.test.testsubjects.Level1; +import io.helidon.builder.test.testsubjects.Level1Impl; +import io.helidon.builder.test.testsubjects.Level1ManualImpl; +import io.helidon.builder.test.testsubjects.Level2; +import io.helidon.builder.test.testsubjects.Level2Impl; +import io.helidon.builder.test.testsubjects.Level2ManualImpl; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/MyConfigBeanTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/MyConfigBeanTest.java similarity index 91% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/MyConfigBeanTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/MyConfigBeanTest.java index 9906b54e3f9..73b73bbe1bd 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/MyConfigBeanTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/MyConfigBeanTest.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; -import io.helidon.pico.builder.test.testsubjects.MyConfigBean; -import io.helidon.pico.builder.test.testsubjects.MyConfigBeanImpl; -import io.helidon.pico.builder.api.test.testsubjects.MyConfigBeanManualImpl; +import io.helidon.builder.test.testsubjects.MyConfigBean; +import io.helidon.builder.test.testsubjects.MyConfigBeanImpl; +import io.helidon.builder.test.testsubjects.MyConfigBeanManualImpl; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/MyDerivedConfigBeanTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/MyDerivedConfigBeanTest.java similarity index 92% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/MyDerivedConfigBeanTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/MyDerivedConfigBeanTest.java index 803a021ec9e..4f310faeb0d 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/MyDerivedConfigBeanTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/MyDerivedConfigBeanTest.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.TreeMap; -import io.helidon.pico.builder.test.testsubjects.MyDerivedConfigBean; -import io.helidon.pico.builder.test.testsubjects.MyDerivedConfigBeanImpl; +import io.helidon.builder.test.testsubjects.MyDerivedConfigBean; +import io.helidon.builder.test.testsubjects.MyDerivedConfigBeanImpl; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ParentParentChildTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/ParentParentChildTest.java similarity index 93% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ParentParentChildTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/ParentParentChildTest.java index d21e019efea..3647b1b0baa 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/ParentParentChildTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/ParentParentChildTest.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; import java.net.URI; import java.util.Optional; -import io.helidon.pico.builder.test.testsubjects.ChildInterfaceIsABuilder; -import io.helidon.pico.builder.test.testsubjects.ChildInterfaceIsABuilderImpl; +import io.helidon.builder.test.testsubjects.ChildInterfaceIsABuilder; +import io.helidon.builder.test.testsubjects.ChildInterfaceIsABuilderImpl; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/PickleBarrelTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/PickleBarrelTest.java similarity index 87% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/PickleBarrelTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/PickleBarrelTest.java index 96efe668b59..be72513a1b7 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/PickleBarrelTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/PickleBarrelTest.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; import java.util.Optional; -import io.helidon.pico.builder.test.testsubjects.DefaultPickle; -import io.helidon.pico.builder.test.testsubjects.DefaultPickleBarrel; -import io.helidon.pico.builder.test.testsubjects.Pickle; -import io.helidon.pico.builder.test.testsubjects.PickleBarrel; +import io.helidon.builder.test.testsubjects.DefaultPickle; +import io.helidon.builder.test.testsubjects.DefaultPickleBarrel; +import io.helidon.builder.test.testsubjects.Pickle; +import io.helidon.builder.test.testsubjects.PickleBarrel; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/UsageTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/UsageTest.java similarity index 79% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/UsageTest.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/UsageTest.java index d862ac20eea..3e9b4900278 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/UsageTest.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/UsageTest.java @@ -14,16 +14,16 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test; +package io.helidon.builder.test; -import io.helidon.pico.builder.test.testsubjects.A; -import io.helidon.pico.builder.test.testsubjects.B; -import io.helidon.pico.builder.test.testsubjects.C; -import io.helidon.pico.builder.test.testsubjects.DefaultA; -import io.helidon.pico.builder.test.testsubjects.DefaultB; -import io.helidon.pico.builder.test.testsubjects.DefaultC; -import io.helidon.pico.builder.test.testsubjects.DefaultT; -import io.helidon.pico.builder.test.testsubjects.T; +import io.helidon.builder.test.testsubjects.A; +import io.helidon.builder.test.testsubjects.B; +import io.helidon.builder.test.testsubjects.C; +import io.helidon.builder.test.testsubjects.DefaultA; +import io.helidon.builder.test.testsubjects.DefaultB; +import io.helidon.builder.test.testsubjects.DefaultC; +import io.helidon.builder.test.testsubjects.DefaultT; +import io.helidon.builder.test.testsubjects.T; import org.junit.jupiter.api.Test; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level0ManualImpl.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level0ManualImpl.java similarity index 93% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level0ManualImpl.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level0ManualImpl.java index 0edf327adff..4835de2b9af 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level0ManualImpl.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level0ManualImpl.java @@ -14,14 +14,12 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Supplier; -import io.helidon.pico.builder.test.testsubjects.Level0; - /** * Example of what would be code generated by the builder. Used in testing. */ @@ -53,10 +51,10 @@ public boolean equals(Object another) { if (this == another) { return true; } - if (!(another instanceof io.helidon.pico.builder.test.testsubjects.Level0)) { + if (!(another instanceof Level0)) { return false; } - io.helidon.pico.builder.test.testsubjects.Level0 other = (io.helidon.pico.builder.test.testsubjects.Level0) another; + Level0 other = (Level0) another; boolean equals = true; equals &= Objects.equals(getLevel0StringAttribute(), other.getLevel0StringAttribute()); return equals; diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level1ManualImpl.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level1ManualImpl.java similarity index 95% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level1ManualImpl.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level1ManualImpl.java index 0bdd3c11b3e..4d354aac3c0 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level1ManualImpl.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level1ManualImpl.java @@ -14,13 +14,11 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Objects; import java.util.Optional; -import io.helidon.pico.builder.test.testsubjects.Level1; - /** * Example of what would be code generated by the builder. Used in testing. */ @@ -62,10 +60,10 @@ public boolean equals(Object another) { if (this == another) { return true; } - if (!(another instanceof io.helidon.pico.builder.test.testsubjects.Level1)) { + if (!(another instanceof Level1)) { return false; } - io.helidon.pico.builder.test.testsubjects.Level1 other = (io.helidon.pico.builder.test.testsubjects.Level1) another; + Level1 other = (Level1) another; boolean equals = super.equals(other); equals &= Objects.equals(getLevel1intAttribute(), other.getLevel1intAttribute()); equals &= Objects.equals(getLevel1IntegerAttribute(), other.getLevel1IntegerAttribute()); diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level2ManualImpl.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level2ManualImpl.java similarity index 95% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level2ManualImpl.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level2ManualImpl.java index 7fe0aa80966..da8673d9c12 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/Level2ManualImpl.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/Level2ManualImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Collection; import java.util.Collections; @@ -24,10 +24,6 @@ import java.util.Map; import java.util.Objects; -import io.helidon.pico.builder.test.testsubjects.Level0; -import io.helidon.pico.builder.test.testsubjects.Level1; -import io.helidon.pico.builder.test.testsubjects.Level2; - /** * Example of what would be code generated by the builder. Used in testing. */ @@ -65,10 +61,10 @@ public boolean equals(Object another) { if (this == another) { return true; } - if (!(another instanceof io.helidon.pico.builder.test.testsubjects.Level2)) { + if (!(another instanceof Level2)) { return false; } - io.helidon.pico.builder.test.testsubjects.Level2 other = (io.helidon.pico.builder.test.testsubjects.Level2) another; + Level2 other = (Level2) another; boolean equals = super.equals(other); equals &= Objects.equals(getLevel2Level0Info(), other.getLevel2Level0Info()); equals &= Objects.equals(getLevel2ListOfLevel0s(), other.getLevel2ListOfLevel0s()); diff --git a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/MyConfigBeanManualImpl.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/MyConfigBeanManualImpl.java similarity index 97% rename from pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/MyConfigBeanManualImpl.java rename to builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/MyConfigBeanManualImpl.java index 36762d30918..354b37672d0 100644 --- a/pico/builder/tests/builder/src/test/java/io/helidon/pico/builder/api/test/testsubjects/MyConfigBeanManualImpl.java +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/testsubjects/MyConfigBeanManualImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.api.test.testsubjects; +package io.helidon.builder.test.testsubjects; import java.util.Arrays; import java.util.Collections; @@ -22,8 +22,6 @@ import java.util.Map; import java.util.Objects; -import io.helidon.pico.builder.test.testsubjects.MyConfigBean; - /** * Example of what would be code generated by the builder. Used in testing. */ diff --git a/pico/builder/tests/pom.xml b/builder/tests/pom.xml similarity index 84% rename from pico/builder/tests/pom.xml rename to builder/tests/pom.xml index 72894e24189..ae271e397dc 100644 --- a/pico/builder/tests/pom.xml +++ b/builder/tests/pom.xml @@ -23,17 +23,17 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - io.helidon.pico.builder - helidon-pico-builder-project + io.helidon.builder + helidon-builder-project 4.0.0-SNAPSHOT ../pom.xml 4.0.0 - io.helidon.pico.builder.tests - helidon-pico-builder-tests-project + io.helidon.builder.tests + helidon-builder-tests-project - Helidon Pico Builder Tests Project + Helidon Builder Tests Project pom diff --git a/pico/builder-config/builder-config/pom.xml b/pico/builder-config/builder-config/pom.xml index 8918384dd6e..a931c08bfe8 100644 --- a/pico/builder-config/builder-config/pom.xml +++ b/pico/builder-config/builder-config/pom.xml @@ -40,8 +40,13 @@ - io.helidon.pico.builder - helidon-pico-builder + io.helidon.builder + helidon-builder + + + io.helidon.builder + helidon-builder-processor + provided io.helidon.common @@ -88,8 +93,8 @@ true - io.helidon.pico.builder - helidon-pico-builder-processor + io.helidon.builder + helidon-builder-processor ${helidon.version} diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java index ae24ae907a6..14a5ce61d88 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/ConfigBean.java @@ -21,13 +21,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import io.helidon.pico.builder.BuilderTrigger; +import io.helidon.builder.BuilderTrigger; /** - * A {@code ConfigBean} is another {@link io.helidon.pico.builder.BuilderTrigger} which extends the - * {@link io.helidon.pico.builder.Builder} concept in support of integration to Helidon's configuration sub-system. It provides - * everything that {@link io.helidon.pico.builder.Builder} provides. However, unlike the base - * {@link io.helidon.pico.builder.Builder} generated classes which can handle any object type, the types used within your target + * A {@code ConfigBean} is another {@link io.helidon.builder.BuilderTrigger} which extends the + * {@link io.helidon.builder.Builder} concept in support of integration to Helidon's configuration sub-system. It provides + * everything that {@link io.helidon.builder.Builder} provides. However, unlike the base + * {@link io.helidon.builder.Builder} generated classes which can handle any object type, the types used within your target * {@code ConfigBean}-annotated interface must have all of its attribute getter method types resolvable by Helidon's configuration * sub-system. *

    diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java index 9d0a38d42a7..7f6c6c372d5 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java @@ -21,7 +21,7 @@ import java.util.Objects; import java.util.function.Supplier; -import io.helidon.pico.builder.AttributeVisitor; +import io.helidon.builder.AttributeVisitor; /** * Validates a {@link io.helidon.pico.builder.config.ConfigBean} generated builder type instance bean the builder build() is diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java index aa03bd9d607..8a9c6482a90 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanInfo.java @@ -18,12 +18,12 @@ import java.util.Objects; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; import io.helidon.pico.builder.config.ConfigBean; /** * Represents all the attributes belonging to {@link io.helidon.pico.builder.config.ConfigBean} available in a - * {@link io.helidon.pico.builder.Builder} style usage pattern. + * {@link io.helidon.builder.Builder} style usage pattern. */ @Builder(implPrefix = "Meta") public interface ConfigBeanInfo extends ConfigBean { diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java index b1b12ff1b7d..dfa0434dd75 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverMapRequest.java @@ -18,7 +18,7 @@ import java.util.Optional; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * An extension of {@link io.helidon.pico.builder.config.spi.ConfigResolverRequest} for handling {@link java.util.Map}-like diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java index 4c200077b3f..fd1a19c37c2 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverRequest.java @@ -18,7 +18,7 @@ import java.util.Optional; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Used in conjunction with {@link io.helidon.pico.builder.config.spi.ConfigResolver}. diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java index 7fb8dd030a6..f21f045a12b 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java @@ -20,7 +20,7 @@ import io.helidon.common.config.Config; import io.helidon.common.config.spi.ConfigProvider; -import io.helidon.pico.builder.AttributeVisitor; +import io.helidon.builder.AttributeVisitor; /** * These methods are in common between generated config bean and config bean builder types. @@ -51,7 +51,7 @@ public interface GeneratedConfigCommon extends ConfigProvider { Class __configBeanType(); /** - * Visits all attributes with the provided {@link io.helidon.pico.builder.AttributeVisitor}. + * Visits all attributes with the provided {@link io.helidon.builder.AttributeVisitor}. * * @param visitor the visitor * @param userDefinedCtx any user-defined context diff --git a/pico/builder-config/builder-config/src/main/java/module-info.java b/pico/builder-config/builder-config/src/main/java/module-info.java index 67c804cda28..8eb222c048a 100644 --- a/pico/builder-config/builder-config/src/main/java/module-info.java +++ b/pico/builder-config/builder-config/src/main/java/module-info.java @@ -19,7 +19,7 @@ */ module io.helidon.pico.builder.config { requires static jakarta.inject; - requires io.helidon.pico.builder; + requires io.helidon.builder; requires io.helidon.common; requires io.helidon.common.config; diff --git a/pico/builder-config/processor/pom.xml b/pico/builder-config/processor/pom.xml index b5edbd42e46..2fc0bf0d6fc 100644 --- a/pico/builder-config/processor/pom.xml +++ b/pico/builder-config/processor/pom.xml @@ -38,8 +38,8 @@ helidon-pico-builder-config - io.helidon.pico.builder - helidon-pico-builder-processor + io.helidon.builder + helidon-builder-processor io.helidon.pico diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java index 65394f33cd6..c23417a1784 100644 --- a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java @@ -43,9 +43,9 @@ import io.helidon.pico.builder.config.spi.GeneratedConfigBeanBuilderBase; import io.helidon.pico.builder.config.spi.MetaConfigBeanInfo; import io.helidon.pico.builder.config.spi.ResolutionCtx; -import io.helidon.pico.builder.processor.spi.TypeInfo; -import io.helidon.pico.builder.processor.tools.BodyContext; -import io.helidon.pico.builder.processor.tools.DefaultBuilderCreator; +import io.helidon.builder.processor.spi.TypeInfo; +import io.helidon.builder.processor.tools.BodyContext; +import io.helidon.builder.processor.tools.DefaultBuilderCreator; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; import io.helidon.pico.types.DefaultTypeName; diff --git a/pico/builder-config/processor/src/main/java/module-info.java b/pico/builder-config/processor/src/main/java/module-info.java index ad05aef5373..5d740b78532 100644 --- a/pico/builder-config/processor/src/main/java/module-info.java +++ b/pico/builder-config/processor/src/main/java/module-info.java @@ -23,16 +23,16 @@ requires io.helidon.common.config; requires io.helidon.config.metadata; requires io.helidon.pico.builder.config; - requires io.helidon.pico.builder.processor; - requires io.helidon.pico.builder.processor.spi; - requires io.helidon.pico.builder.processor.tools; + requires io.helidon.builder.processor; + requires io.helidon.builder.processor.spi; + requires io.helidon.builder.processor.tools; requires io.helidon.pico.types; requires io.helidon.pico; exports io.helidon.pico.builder.config.processor.tools; - uses io.helidon.pico.builder.processor.spi.BuilderCreator; + uses io.helidon.builder.processor.spi.BuilderCreator; - provides io.helidon.pico.builder.processor.spi.BuilderCreator + provides io.helidon.builder.processor.spi.BuilderCreator with io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; } diff --git a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java index 5d921d05f3c..68607bec862 100644 --- a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java +++ b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java @@ -18,7 +18,7 @@ import io.helidon.pico.builder.config.ConfigBean; import io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; -import io.helidon.pico.builder.processor.spi.BuilderCreator; +import io.helidon.builder.processor.spi.BuilderCreator; import org.junit.jupiter.api.Test; diff --git a/pico/builder-config/tests/configbean/src/main/java/module-info.java b/pico/builder-config/tests/configbean/src/main/java/module-info.java index 0db7b6f92a7..e8fd093bb5f 100644 --- a/pico/builder-config/tests/configbean/src/main/java/module-info.java +++ b/pico/builder-config/tests/configbean/src/main/java/module-info.java @@ -27,5 +27,5 @@ requires io.helidon.common.config; requires io.helidon.pico; requires io.helidon.pico.builder.config; - requires io.helidon.pico.builder; + requires io.helidon.builder; } diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java index 05c0330801b..f0f889ace61 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeComponentTracingConfig.java @@ -18,7 +18,7 @@ import java.util.Map; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Singular; import io.helidon.pico.builder.config.ConfigBean; /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java index fefe6cfd5cb..9c4381e9054 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeyConfig.java @@ -22,7 +22,7 @@ import java.util.List; import java.util.Optional; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * aka KeyConfig. diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java index bd02e890646..a9a9122ab52 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeKeystoreConfig.java @@ -19,7 +19,7 @@ import java.util.List; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Singular; import io.helidon.pico.builder.config.ConfigBean; /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java index 1f1a094d05a..5380490a25a 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakePathTracingConfig.java @@ -19,7 +19,7 @@ import java.util.List; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Singular; import io.helidon.pico.builder.config.ConfigBean; /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java index b1099652728..4fe9a780c2d 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeServerConfig.java @@ -21,7 +21,7 @@ import java.util.Optional; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Singular; import io.helidon.pico.builder.config.ConfigBean; /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java index db45e5b1746..d71487a43a1 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeSpanTracingConfig.java @@ -19,7 +19,7 @@ import java.util.Map; import java.util.Optional; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Singular; import io.helidon.pico.builder.config.ConfigBean; /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java index d99c5280f62..00bc2569286 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeTracingConfig.java @@ -18,7 +18,7 @@ import java.util.Map; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Singular; import io.helidon.pico.builder.config.ConfigBean; /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java index 55df6d15b72..6b7e05e4798 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/FakeWebServerTlsConfig.java @@ -24,7 +24,7 @@ import javax.net.ssl.SSLContext; import io.helidon.common.LazyValue; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Singular; import io.helidon.pico.builder.config.ConfigBean; /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java index 760b0942b74..353d7af35a6 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/fakes/SSLContextConfig.java @@ -18,7 +18,7 @@ import java.util.Random; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * aka SSLContextBuilder. diff --git a/pico/pico/pom.xml b/pico/pico/pom.xml index 9e4ea08b8ad..a80c4895f56 100644 --- a/pico/pico/pom.xml +++ b/pico/pico/pom.xml @@ -61,13 +61,13 @@ true - io.helidon.pico.builder - helidon-pico-builder + io.helidon.builder + helidon-builder provided - io.helidon.pico.builder - helidon-pico-builder-processor + io.helidon.builder + helidon-builder-processor provided @@ -95,8 +95,8 @@ - io.helidon.pico.builder - helidon-pico-builder-processor + io.helidon.builder + helidon-builder-processor ${helidon.version} diff --git a/pico/pico/src/main/java/io/helidon/pico/ActivationLogEntry.java b/pico/pico/src/main/java/io/helidon/pico/ActivationLogEntry.java index 3daacb8b4da..ec0ee0ed6b8 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ActivationLogEntry.java +++ b/pico/pico/src/main/java/io/helidon/pico/ActivationLogEntry.java @@ -19,7 +19,7 @@ import java.time.Instant; import java.util.Optional; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Log entry for lifecycle related events (i.e., activation startup and deactivation shutdown). diff --git a/pico/pico/src/main/java/io/helidon/pico/ActivationRequest.java b/pico/pico/src/main/java/io/helidon/pico/ActivationRequest.java index daecb5267cf..bf81d0a4be5 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ActivationRequest.java +++ b/pico/pico/src/main/java/io/helidon/pico/ActivationRequest.java @@ -19,7 +19,7 @@ import java.util.Optional; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Request to activate a service. diff --git a/pico/pico/src/main/java/io/helidon/pico/ActivationResult.java b/pico/pico/src/main/java/io/helidon/pico/ActivationResult.java index bd0d600c1af..5aea248deee 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ActivationResult.java +++ b/pico/pico/src/main/java/io/helidon/pico/ActivationResult.java @@ -20,7 +20,7 @@ import java.util.Optional; import java.util.concurrent.Future; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Represents the result of a service activation or deactivation. diff --git a/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java b/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java index 40d35485ef8..9d5a866c5df 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java +++ b/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java @@ -16,7 +16,7 @@ package io.helidon.pico; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Combines the {@link io.helidon.pico.ServiceInfo} criteria along with the {@link io.helidon.pico.InjectionPointInfo} context diff --git a/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java b/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java index e1e60e8926c..f8dccd9c640 100644 --- a/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java +++ b/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java @@ -17,7 +17,7 @@ package io.helidon.pico; import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Request to {@link io.helidon.pico.DeActivator#deactivate(DeActivationRequest)}. diff --git a/pico/pico/src/main/java/io/helidon/pico/DependencyInfo.java b/pico/pico/src/main/java/io/helidon/pico/DependencyInfo.java index 593f273a326..9e7b417a50f 100644 --- a/pico/pico/src/main/java/io/helidon/pico/DependencyInfo.java +++ b/pico/pico/src/main/java/io/helidon/pico/DependencyInfo.java @@ -18,7 +18,7 @@ import java.util.Set; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Aggregates the set of {@link InjectionPointInfo}'s that are dependent upon a specific and common diff --git a/pico/pico/src/main/java/io/helidon/pico/ElementInfo.java b/pico/pico/src/main/java/io/helidon/pico/ElementInfo.java index e17c2263c59..40df5a34650 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ElementInfo.java +++ b/pico/pico/src/main/java/io/helidon/pico/ElementInfo.java @@ -19,7 +19,7 @@ import java.util.Optional; import java.util.Set; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; import io.helidon.pico.types.AnnotationAndValue; /** diff --git a/pico/pico/src/main/java/io/helidon/pico/InjectionPointInfo.java b/pico/pico/src/main/java/io/helidon/pico/InjectionPointInfo.java index 82fddc705e7..5df97f2b3d8 100644 --- a/pico/pico/src/main/java/io/helidon/pico/InjectionPointInfo.java +++ b/pico/pico/src/main/java/io/helidon/pico/InjectionPointInfo.java @@ -18,7 +18,7 @@ import java.util.Set; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Describes a receiver for injection - identifies who/what is requesting an injection that needs to be satisfied. diff --git a/pico/pico/src/main/java/io/helidon/pico/InjectorOptions.java b/pico/pico/src/main/java/io/helidon/pico/InjectorOptions.java index ac35dfb938d..726619363a9 100644 --- a/pico/pico/src/main/java/io/helidon/pico/InjectorOptions.java +++ b/pico/pico/src/main/java/io/helidon/pico/InjectorOptions.java @@ -18,7 +18,7 @@ import java.util.Optional; -import io.helidon.pico.builder.Builder; +import io.helidon.builder.Builder; /** * Provides optional, contextual tunings to the {@link Injector}. diff --git a/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java b/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java index 1fa862b3b49..b43a1c64846 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java +++ b/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java @@ -19,8 +19,8 @@ import java.util.Optional; import java.util.Set; -import io.helidon.pico.builder.Builder; -import io.helidon.pico.builder.Singular; +import io.helidon.builder.Builder; +import io.helidon.builder.Singular; /** * A criteria to discover service. diff --git a/pico/pico/src/main/java/module-info.java b/pico/pico/src/main/java/module-info.java index cb89b9efc52..3c7fcb3fed2 100644 --- a/pico/pico/src/main/java/module-info.java +++ b/pico/pico/src/main/java/module-info.java @@ -21,7 +21,7 @@ requires io.helidon.common; requires io.helidon.common.config; requires io.helidon.pico.types; - requires static io.helidon.pico.builder; + requires static io.helidon.builder; requires static io.helidon.config.metadata; requires static jakarta.annotation; diff --git a/pico/pom.xml b/pico/pom.xml index 2f7242dbbfe..27980559b44 100644 --- a/pico/pom.xml +++ b/pico/pom.xml @@ -46,7 +46,6 @@ types - builder builder-config pico diff --git a/pom.xml b/pom.xml index 32bb3490aa1..c97ad189be2 100644 --- a/pom.xml +++ b/pom.xml @@ -200,10 +200,10 @@ reactive cors pico + builder - From 22999107cf62a7d9f9c447c8c248ae13535bcad8 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 29 Nov 2022 15:10:49 -0500 Subject: [PATCH 29/36] checkstyles, formats, and import ordering --- .../processor/tools/BuilderTypeTools.java | 64 ++++++++++--------- .../builder/processor/BuilderProcessor.java | 4 +- .../ChildInterfaceIsABuilder.java | 2 +- .../builder/test/testsubjects/Container.java | 2 +- .../builder/test/testsubjects/EdgeCases.java | 2 +- .../builder/test/testsubjects/Level0.java | 2 +- .../builder/test/testsubjects/Level1.java | 2 +- .../builder/test/testsubjects/Level2.java | 2 +- .../test/testsubjects/MyConfigBean.java | 2 +- .../builder/test/testsubjects/Pickle.java | 2 +- .../config/spi/GeneratedConfigCommon.java | 2 +- .../tools/ConfigBeanBuilderCreator.java | 6 +- .../io/helidon/pico/ActivationRequest.java | 4 +- .../io/helidon/pico/DeActivationRequest.java | 4 +- 14 files changed, 53 insertions(+), 47 deletions(-) diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java index b6382682473..cbcb2b05674 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java @@ -44,11 +44,11 @@ import javax.lang.model.util.Elements; import javax.tools.Diagnostic; -import io.helidon.common.Weight; -import io.helidon.common.Weighted; import io.helidon.builder.processor.spi.DefaultTypeInfo; import io.helidon.builder.processor.spi.TypeInfo; import io.helidon.builder.processor.spi.TypeInfoCreator; +import io.helidon.common.Weight; +import io.helidon.common.Weighted; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; import io.helidon.pico.types.DefaultTypeName; @@ -57,11 +57,12 @@ import io.helidon.pico.types.TypedElementName; /** - * The default implementation for {@link io.helidon.builder.processor.spi.TypeInfoCreator}. This also contains an abundance of other - * useful methods used for annotation processing. + * The default implementation for {@link io.helidon.builder.processor.spi.TypeInfoCreator}. This also contains an abundance of + * other useful methods used for annotation processing. */ @Weight(Weighted.DEFAULT_WEIGHT - 1) public class BuilderTypeTools implements TypeInfoCreator { + /** * Default constructor. */ @@ -103,19 +104,20 @@ public Optional createTypeInfo(AnnotationAndValue annotation, Collection elementInfo = toElementInfo(element, processingEnv); return Optional.of(DefaultTypeInfo.builder() - .typeName(typeName) - .typeKind(String.valueOf(element.getKind())) - .annotations(BuilderTypeTools.createAnnotationAndValueListFromElement(element, processingEnv.getElementUtils())) - .elementInfo(elementInfo) - .update(it -> toTypeInfo(annotation, element, processingEnv).ifPresent(it::superTypeInfo)) - .build()); + .typeName(typeName) + .typeKind(String.valueOf(element.getKind())) + .annotations(BuilderTypeTools.createAnnotationAndValueListFromElement(element, + processingEnv.getElementUtils())) + .elementInfo(elementInfo) + .update(it -> toTypeInfo(annotation, element, processingEnv).ifPresent(it::superTypeInfo)) + .build()); } /** * Translation the arguments to a collection of {@link io.helidon.pico.types.TypedElementName}'s. * - * @param element the typed element (i.e., class) - * @param processingEnv the processing env + * @param element the typed element (i.e., class) + * @param processingEnv the processing env * @return the collection of typed elements */ protected Collection toElementInfo(TypeElement element, ProcessingEnvironment processingEnv) { @@ -130,7 +132,7 @@ protected Collection toElementInfo(TypeElement element, Proces /** * Returns true if the executable element passed is acceptable for processing (i.e., not a static and not a default method). * - * @param ee the executable element + * @param ee the executable element * @return true if not default and not static */ protected boolean canAccept(ExecutableElement ee) { @@ -257,8 +259,8 @@ public static Optional createTypeNameFromMirror(TypeMirror type if (typeMirror instanceof ArrayType) { ArrayType arrayType = (ArrayType) typeMirror; return Optional.of(createTypeNameFromMirror(arrayType.getComponentType()).orElseThrow().toBuilder() - .array(true) - .build()); + .array(true) + .build()); } if (typeMirror instanceof DeclaredType) { @@ -283,12 +285,12 @@ public static Optional createTypeNameFromMirror(TypeMirror type /** * Locate an annotation mirror by name. * - * @param annotationType the annotation type to search for - * @param ams the collection to search through + * @param annotationType the annotation type to search for + * @param ams the collection to search through * @return the annotation mirror, or empty if not found */ public static Optional findAnnotationMirror(String annotationType, - Collection ams) { + Collection ams) { return ams.stream() .filter(it -> annotationType.equals(it.getAnnotationType().toString())) .findFirst(); @@ -297,8 +299,8 @@ public static Optional findAnnotationMirror(String a /** * Creates an instance from an annotation mirror during annotation processing. * - * @param am the annotation mirror - * @param elements the elements + * @param am the annotation mirror + * @param elements the elements * @return the new instance or empty if the annotation mirror passed is invalid */ public static Optional createAnnotationAndValueFromMirror(AnnotationMirror am, @@ -311,8 +313,8 @@ public static Optional createAnnotationAndValueFromMirror(An /** * Creates an instance from a variable element during annotation processing. * - * @param e the variable/type element - * @param elements the elements + * @param e the variable/type element + * @param elements the elements * @return the list of annotations extracted from the element */ public static List createAnnotationAndValueListFromElement(Element e, @@ -326,8 +328,8 @@ public static List createAnnotationAndValueListFromElement(E /** * Extracts values from the annotation mirror value. * - * @param am the annotation mirror - * @param elements the optional elements + * @param am the annotation mirror + * @param elements the optional elements * @return the extracted values */ public static Map extractValues(AnnotationMirror am, @@ -357,8 +359,8 @@ public static Map extractValues(Map { + /** * Target service provider. * @@ -56,4 +57,5 @@ public interface ActivationRequest { */ @ConfiguredOption("true") boolean throwOnFailure(); + } diff --git a/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java b/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java index f8dccd9c640..67facfacbe2 100644 --- a/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java +++ b/pico/pico/src/main/java/io/helidon/pico/DeActivationRequest.java @@ -16,8 +16,8 @@ package io.helidon.pico; -import io.helidon.config.metadata.ConfiguredOption; import io.helidon.builder.Builder; +import io.helidon.config.metadata.ConfiguredOption; /** * Request to {@link io.helidon.pico.DeActivator#deactivate(DeActivationRequest)}. @@ -26,6 +26,7 @@ */ @Builder public interface DeActivationRequest { + /** * Create a request with defaults. * @@ -52,4 +53,5 @@ static DeActivationRequest create(ServiceProvider provider) { */ @ConfiguredOption("true") boolean throwOnFailure(); + } From 728e14ce8179004d29ae609a61b364cdbd822446 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 29 Nov 2022 16:58:22 -0500 Subject: [PATCH 30/36] some review comments addressed --- builder/pom.xml | 15 +++ .../builder/processor/spi/package-info.java | 2 +- .../processor/tools/BuilderTypeTools.java | 5 +- .../tools/DefaultBuilderCreator.java | 2 +- .../test/testsubjects/AnnotationCase.java | 4 +- common/config/pom.xml | 27 ----- .../helidon/common/config/ConfigHolder.java | 105 ------------------ .../common/config/spi/ConfigMapper.java | 42 ------- .../config/spi/ConfigMapperProvider.java | 40 ------- .../common/config/spi/package-info.java | 20 ---- common/config/src/main/java/module-info.java | 6 - .../spi/testsubjects/TestConfigProvider.java | 46 -------- .../common/config/test/ConfigHolderTest.java | 51 --------- ...o.helidon.common.config.spi.ConfigProvider | 17 --- config/config/etc/spotbugs/exclude.xml | 10 -- .../io/helidon/config/spi/ConfigMapper.java | 5 +- .../config/spi/ConfigMapperProvider.java | 5 +- etc/checkstyle-suppressions.xml | 2 +- .../builder-config/etc/spotbugs/exclude.xml | 12 +- ...neratedConfigBean.java => ConfigBean.java} | 4 +- ...onfigBeanBase.java => ConfigBeanBase.java} | 6 +- ...eanBuilder.java => ConfigBeanBuilder.java} | 6 +- ...erBase.java => ConfigBeanBuilderBase.java} | 6 +- ...onfigCommon.java => ConfigBeanCommon.java} | 12 +- .../builder/config/spi/ConfigBeanMapper.java | 9 +- .../config/spi/ConfigBeanMapperHolder.java | 9 +- .../config/spi/ConfigBeanMapperProvider.java | 2 +- .../builder}/config/spi/ConfigProvider.java | 22 ++-- .../src/main/java/module-info.java | 1 + .../tools/ConfigBeanBuilderCreator.java | 12 +- 30 files changed, 81 insertions(+), 424 deletions(-) delete mode 100644 common/config/src/main/java/io/helidon/common/config/ConfigHolder.java delete mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java delete mode 100644 common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java delete mode 100644 common/config/src/main/java/io/helidon/common/config/spi/package-info.java delete mode 100644 common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java delete mode 100644 common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java delete mode 100644 common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider rename pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/{GeneratedConfigBean.java => ConfigBean.java} (92%) rename pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/{GeneratedConfigBeanBase.java => ConfigBeanBase.java} (87%) rename pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/{GeneratedConfigBeanBuilder.java => ConfigBeanBuilder.java} (92%) rename pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/{GeneratedConfigBeanBuilderBase.java => ConfigBeanBuilderBase.java} (90%) rename pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/{GeneratedConfigCommon.java => ConfigBeanCommon.java} (82%) rename {common/config/src/main/java/io/helidon/common => pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder}/config/spi/ConfigProvider.java (52%) diff --git a/builder/pom.xml b/builder/pom.xml index 036f8d3526d..9e7952bce60 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -49,4 +49,19 @@ tests + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + + + + + diff --git a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java index 7c569f5846b..11a24ddee05 100644 --- a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java @@ -17,7 +17,7 @@ /** * The Pico Builder Processor SPI module provides these definitions: *

      - *
    1. {@link io.helidon.pico.builder.processor.spi.BuilderCreator} - responsible for code generating the implementation w/ + *
    2. {@link io.helidon.builder.processor.spi.BuilderCreator} - responsible for code generating the implementation w/ * a fluent builder.
    3. *
    4. {@link io.helidon.builder.processor.spi.TypeInfoCreator} - responsible for code generating the model object for * the target interface.
    5. diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java index cbcb2b05674..3542de520b4 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java @@ -106,8 +106,9 @@ public Optional createTypeInfo(AnnotationAndValue annotation, return Optional.of(DefaultTypeInfo.builder() .typeName(typeName) .typeKind(String.valueOf(element.getKind())) - .annotations(BuilderTypeTools.createAnnotationAndValueListFromElement(element, - processingEnv.getElementUtils())) + .annotations(BuilderTypeTools + .createAnnotationAndValueListFromElement(element, + processingEnv.getElementUtils())) .elementInfo(elementInfo) .update(it -> toTypeInfo(annotation, element, processingEnv).ifPresent(it::superTypeInfo)) .build()); diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java index 09f744acf22..78a80c0967f 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java @@ -52,7 +52,7 @@ import static io.helidon.builder.processor.tools.BodyContext.toBeanAttributeName; /** - * Default implementation for {@link io.helidon.pico.builder.processor.spi.BuilderCreator}. + * Default implementation for {@link BuilderCreator}. */ @Weight(Weighted.DEFAULT_WEIGHT - 1) // allow all other creators to take precedence over us... public class DefaultBuilderCreator implements BuilderCreator { diff --git a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCase.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCase.java index 53042f1e457..0094036633a 100644 --- a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCase.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/AnnotationCase.java @@ -27,7 +27,7 @@ * Also demonstrates how default values are handled on the generated builder. * * @return "hello" - * @see io.helidon.pico.builder.test.testsubjects.DefaultAnnotationCaseExt (generated code) + * @see DefaultAnnotationCaseExt (generated code) */ String value() default "hello"; @@ -35,7 +35,7 @@ * Demonstrates how string array defaults work on the generated builder. * * @return "a", "b", "c" - * @see io.helidon.pico.builder.test.testsubjects.DefaultAnnotationCaseExt (generated code) + * @see DefaultAnnotationCaseExt (generated code) */ String[] strArr() default {"a", "b", "c"}; diff --git a/common/config/pom.xml b/common/config/pom.xml index 4ee63f3e723..8657f6c8175 100644 --- a/common/config/pom.xml +++ b/common/config/pom.xml @@ -33,33 +33,6 @@ 11 - - - io.helidon.common - helidon-common - - - jakarta.inject - jakarta.inject-api - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.mockito - mockito-core - test - - - diff --git a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java b/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java deleted file mode 100644 index 753c66fefb7..00000000000 --- a/common/config/src/main/java/io/helidon/common/config/ConfigHolder.java +++ /dev/null @@ -1,105 +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.common.config; - -import java.util.Objects; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.common.config.spi.ConfigProvider; - -/** - * Provides access to the global {@link io.helidon.common.config.Config} singleton instance. - *

      - * Most callers are simply expected to call the {@link #config()} method to resolve the global configuration. Note, however, - * that the global configuration instance needs to be made available prior to calling the {@link #config()} method. There are - * two techniques for establishing the global configuration instance: (1) via the Java {@link java.util.ServiceLoader} and - * (2) programmatically via the {@link #config(io.helidon.common.config.Config)} method. The {@link #config()} method will - * apply the following strategy to resolve and cache the global config instance: - *

        - *
      1. if the instance has already been established and cached then use it.
      2. - *
      3. if the instance has programmatically been set then use it - this is the same as the cached instance.
      4. - *
      5. use the service loader to resolve the config instance, and if found then cache it.
      6. - *
      - * Note also that the {@link #reset()} method can be used to clear the cached instance. However, doing so should not be expected - * to alter any callers that have previously obtained the global configuration instance prior to calling the {@link #reset()} - * method. - *

      - * Note that this class is not thread safe. If the global configuration must be set programmatically then it should therefore - * be set on the main thread, and typically early in the jvm lifecycle. - * - * @see io.helidon.common.config.spi.ConfigProvider - */ -public class ConfigHolder { - private static final AtomicReference> INSTANCE = new AtomicReference<>(); - - private ConfigHolder() { - } - - /** - * Returns the global {@link io.helidon.common.config.Config} instance. - * - * @return the global instance - */ - public static Optional config() { - if (Objects.isNull(INSTANCE.get())) { - INSTANCE.set(load()); - } - return INSTANCE.get(); - } - - /** - * Proactively set the global configuration instance. Callers are reminded that {@link #reset()} must be called in order - * to clear any previously set global instance. Failure to do so will result in an exception being thrown. - * - * @param cfg the configuration - * @throws java.lang.IllegalStateException called if the config instance was previously been set - */ - public static void config(Config cfg) { - boolean set = INSTANCE.compareAndSet(null, - Optional.of(Objects.requireNonNull(cfg))); - if (!set) { - throw new IllegalStateException(Config.class.getSimpleName() + " already set"); - } - } - - /** - * Clears the config instance; not recommended for common use. - */ - public static void reset() { - System.Logger.Level level = Objects.nonNull(INSTANCE.get()) ? System.Logger.Level.INFO : System.Logger.Level.DEBUG; - System.Logger logger = System.getLogger(ConfigHolder.class.getName()); - logger.log(level, "resetting..."); - INSTANCE.set(null); - } - - private static Optional load() { - Optional provider = HelidonServiceLoader - .create(ServiceLoader.load(ConfigProvider.class, ConfigProvider.class.getClassLoader())) - .asList() - .stream() - .findFirst(); - if (provider.isEmpty()) { - return Optional.empty(); - } - - return provider.get().__config(); - } - -} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java deleted file mode 100644 index 5dffb4e8b7d..00000000000 --- a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapper.java +++ /dev/null @@ -1,42 +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.common.config.spi; - -import io.helidon.common.config.Config; -import io.helidon.common.config.ConfigException; - -/** - * Config mapper is provided to {@link ConfigMapperProvider} to help transformation of - * complex structures. - * - * @param the Config type - */ -@FunctionalInterface -public interface ConfigMapper { - - /** - * Converts the specified {@code Config} node to the target type. - * - * @param config config node to be transformed - * @param type type to which the config node is to be transformed - * @param type to which the config node is to be transformed - * @return transformed value of type {@code T}; never returns {@code null} - * @throws io.helidon.common.config.ConfigException if any issues occur in mapping - */ - T map(C config, Class type) throws ConfigException; - -} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java b/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java deleted file mode 100644 index 3ec6a715764..00000000000 --- a/common/config/src/main/java/io/helidon/common/config/spi/ConfigMapperProvider.java +++ /dev/null @@ -1,40 +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.common.config.spi; - -import java.util.Map; -import java.util.function.Function; - -import io.helidon.common.config.Config; - -/** - * Provides mapping functions that convert a {@code Config} - * subtree to specific Java types. - * - * @param the Config type - */ -@FunctionalInterface -public interface ConfigMapperProvider { - - /** - * Returns a map of mapper functions associated with appropriate target type ({@code Class}. - * - * @return a map of config mapper functions, never {@code null} - */ - Map, Function> mappers(); - -} diff --git a/common/config/src/main/java/io/helidon/common/config/spi/package-info.java b/common/config/src/main/java/io/helidon/common/config/spi/package-info.java deleted file mode 100644 index 387ce4be611..00000000000 --- a/common/config/src/main/java/io/helidon/common/config/spi/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. - */ - -/** - * Common Config SPI. - */ -package io.helidon.common.config.spi; diff --git a/common/config/src/main/java/module-info.java b/common/config/src/main/java/module-info.java index 74bcf4c599e..789c2d599f3 100644 --- a/common/config/src/main/java/module-info.java +++ b/common/config/src/main/java/module-info.java @@ -18,11 +18,5 @@ * Helidon Common Config Library. */ module io.helidon.common.config { - requires io.helidon.common; - - uses io.helidon.common.config.spi.ConfigMapperProvider; - uses io.helidon.common.config.spi.ConfigProvider; - exports io.helidon.common.config; - exports io.helidon.common.config.spi; } diff --git a/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java b/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java deleted file mode 100644 index b23b02af85b..00000000000 --- a/common/config/src/test/java/io/helidon/common/config/spi/testsubjects/TestConfigProvider.java +++ /dev/null @@ -1,46 +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.common.config.spi.testsubjects; - -import java.util.Optional; - -import io.helidon.common.config.Config; -import io.helidon.common.config.ConfigValue; -import io.helidon.common.config.spi.ConfigProvider; - -import jakarta.inject.Singleton; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@Singleton -@SuppressWarnings("unchecked") -@Deprecated -public class TestConfigProvider implements ConfigProvider { - - @Override - public Optional __config() { - ConfigValue val = mock(ConfigValue.class); - when(val.get()).thenReturn("mock"); - - Config cfg = mock(Config.class); - when(cfg.asString()).thenReturn(val); - - return Optional.of(cfg); - } - -} diff --git a/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java b/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java deleted file mode 100644 index 077baf6216a..00000000000 --- a/common/config/src/test/java/io/helidon/common/config/test/ConfigHolderTest.java +++ /dev/null @@ -1,51 +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.common.config.test; - -import java.util.Optional; - -import io.helidon.common.config.Config; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.config.ConfigHolder.config; -import static io.helidon.common.config.ConfigHolder.reset; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.sameInstance; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; - -class ConfigHolderTest { - - @Test - void testConfig() { - Optional cfg = config(); - assertThat(cfg.orElseThrow().asString().get(), is("mock")); - - Config mockCfg = mock(Config.class); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> config(mockCfg)); - assertThat(e.getMessage(), - equalTo(Config.class.getSimpleName() + " already set")); - - reset(); - config(mockCfg); - assertThat(config().orElseThrow(), sameInstance(mockCfg)); - } - -} diff --git a/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider b/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider deleted file mode 100644 index 10c33bdb78d..00000000000 --- a/common/config/src/test/resources/META-INF/services/io.helidon.common.config.spi.ConfigProvider +++ /dev/null @@ -1,17 +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. -# - -io.helidon.common.config.spi.testsubjects.TestConfigProvider diff --git a/config/config/etc/spotbugs/exclude.xml b/config/config/etc/spotbugs/exclude.xml index 2f8695941ca..5e1451958f9 100644 --- a/config/config/etc/spotbugs/exclude.xml +++ b/config/config/etc/spotbugs/exclude.xml @@ -103,15 +103,5 @@ - - - - - - - - - - diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java index 067cf3768d4..b4c3a263c79 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. + * 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. @@ -27,7 +27,7 @@ * Config mapper is provided to {@link ConfigMapperProvider} to help transformation of * complex structures. */ -public interface ConfigMapper extends io.helidon.common.config.spi.ConfigMapper { +public interface ConfigMapper { /** * Convert the specified {@code Config} node into the target type specified by {@link GenericType}. @@ -60,7 +60,6 @@ public interface ConfigMapper extends io.helidon.common.config.spi.ConfigMapper< * @throws ConfigMappingException in case the mapper fails to map the existing configuration value * to an instance of a given Java type */ - @Override T map(Config config, Class type) throws MissingValueException, ConfigMappingException; /** diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java index d43eea3fce1..86f8d140cef 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. + * 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. @@ -43,7 +43,7 @@ * @see Config.Builder#disableMapperServices() */ @FunctionalInterface -public interface ConfigMapperProvider extends io.helidon.common.config.spi.ConfigMapperProvider { +public interface ConfigMapperProvider { /** * Default priority of the mapper provider if registered by {@link Config.Builder} automatically. */ @@ -59,7 +59,6 @@ public interface ConfigMapperProvider extends io.helidon.common.config.spi.Confi * @return a map of config mapper functions, never {@code null}, though this may return an empty map if * {@link #mapper(Class)} is used instead */ - @Override Map, Function> mappers(); /** diff --git a/etc/checkstyle-suppressions.xml b/etc/checkstyle-suppressions.xml index ffc6a4e56ea..b4f66729bb0 100644 --- a/etc/checkstyle-suppressions.xml +++ b/etc/checkstyle-suppressions.xml @@ -78,7 +78,7 @@ checks="ParameterNumber"/> - diff --git a/pico/builder-config/builder-config/etc/spotbugs/exclude.xml b/pico/builder-config/builder-config/etc/spotbugs/exclude.xml index 8bf694d04c5..e8153d5c645 100644 --- a/pico/builder-config/builder-config/etc/spotbugs/exclude.xml +++ b/pico/builder-config/builder-config/etc/spotbugs/exclude.xml @@ -26,8 +26,14 @@ Initialization vector is not static. --> - - - + + + + + + + + + diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBean.java similarity index 92% rename from pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java rename to pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBean.java index 5fd2849c017..19ee7c36cdb 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBean.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBean.java @@ -17,13 +17,11 @@ package io.helidon.pico.builder.config.spi; /** - * Reserved for internal use! - *

      * Every {@link io.helidon.pico.builder.config.ConfigBean}-annotated type will also implement this contract. * * @deprecated this is for internal use only */ -public interface GeneratedConfigBean extends GeneratedConfigCommon { +public interface ConfigBean extends ConfigBeanCommon { /* Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBase.java similarity index 87% rename from pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java rename to pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBase.java index 9c07c600b79..309e869cc60 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBase.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBase.java @@ -22,18 +22,18 @@ import io.helidon.common.config.Config; /** - * Minimal implementation for the {@link GeneratedConfigCommon}. This is the base for generated config beans. + * Minimal implementation for the {@link ConfigBeanCommon}. This is the base for generated config beans. * * @deprecated this is for internal use only */ -public abstract class GeneratedConfigBeanBase implements GeneratedConfigCommon { +public abstract class ConfigBeanBase implements ConfigBeanCommon { private Config cfg; private String instanceId; /** * Protected constructor for initializing the generated config bean instance variables. */ - protected GeneratedConfigBeanBase() { + protected ConfigBeanBase() { } @Override diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilder.java similarity index 92% rename from pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java rename to pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilder.java index e1e302d1709..8792a9e7930 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilder.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilder.java @@ -19,13 +19,11 @@ import io.helidon.common.config.Config; /** - * Reserved for internal use! - *

      - * Every {@link io.helidon.pico.builder.config.ConfigBean}-annotated type will also implement this contract. + * Every {@link io.helidon.pico.builder.config.ConfigBean}-annotated *builder* type will implement this contract. * * @deprecated */ -public interface GeneratedConfigBeanBuilder extends GeneratedConfigCommon { +public interface ConfigBeanBuilder extends ConfigBeanCommon { /* Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java similarity index 90% rename from pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java rename to pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java index ad31a26f906..700f1240c74 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigBeanBuilderBase.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java @@ -19,16 +19,16 @@ import io.helidon.common.config.Config; /** - * Minimal implementation for the {@link GeneratedConfigBeanBuilder}. + * Minimal implementation for the {@link ConfigBeanBuilder}. * * @deprecated this is for internal use only */ -public abstract class GeneratedConfigBeanBuilderBase extends GeneratedConfigBeanBase implements GeneratedConfigBeanBuilder { +public abstract class ConfigBeanBuilderBase extends ConfigBeanBase implements ConfigBeanBuilder { /** * Default constructor. Reserved for internal use. */ - protected GeneratedConfigBeanBuilderBase() { + protected ConfigBeanBuilderBase() { } @Override diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java similarity index 82% rename from pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java rename to pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java index ce23e862806..580c10ccee6 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/GeneratedConfigCommon.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java @@ -20,14 +20,14 @@ import io.helidon.builder.AttributeVisitor; import io.helidon.common.config.Config; -import io.helidon.common.config.spi.ConfigProvider; /** - * These methods are in common between generated config bean and config bean builder types. + * These methods are common between generated {@link io.helidon.pico.builder.config.ConfigBean}-annotated type, as well + * as the associated builder for the same. * * @deprecated this is for internal use only */ -public interface GeneratedConfigCommon extends ConfigProvider { +public interface ConfigBeanCommon extends ConfigProvider { /* Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated @@ -36,15 +36,15 @@ public interface GeneratedConfigCommon extends ConfigProvider { */ /** - * Returns the configuration assigned to the generated config bean. + * Returns any configuration assigned. * - * @return the configuration assigned + * @return the optional configuration assigned */ @Override Optional __config(); /** - * Returns the {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. + * Returns the {@link io.helidon.pico.builder.config.ConfigBean}-annotated type, * * @return the config bean type */ diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java index 911938639ce..e806ecdaf43 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapper.java @@ -17,26 +17,23 @@ package io.helidon.pico.builder.config.spi; import io.helidon.common.config.Config; -import io.helidon.common.config.spi.ConfigMapper; /** * Maps a {@link io.helidon.common.config.Config} instance to a newly created * {@link io.helidon.pico.builder.config.ConfigBean}-annotated type instance. - * - * @param the config type */ @FunctionalInterface -public interface ConfigBeanMapper extends ConfigMapper { +public interface ConfigBeanMapper /* extends ConfigMapper */ { /** * Translate the provided configuration into the appropriate config bean for this service type. * * @param cfg the config * @param configBeanType the config bean type + * @param the config type * @param the config bean type * @return the config bean generated */ - @Override - T map(C cfg, Class configBeanType); + T map(C cfg, Class configBeanType); } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java index d27d863b003..03627556c63 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java @@ -28,7 +28,7 @@ * @see ConfigBeanMapperProvider */ public class ConfigBeanMapperHolder { - private static final LazyValue>> INSTANCE = LazyValue.create(ConfigBeanMapperHolder::load); + private static final LazyValue> INSTANCE = LazyValue.create(ConfigBeanMapperHolder::load); private ConfigBeanMapperHolder() { } @@ -42,15 +42,14 @@ private ConfigBeanMapperHolder() { * type at some point in the future. * * @param configBeanType the config bean type to map - * @param the config bean type * @return the config bean mapper */ @SuppressWarnings({"rawTypes", "unchecked"}) - public static Optional configBeanMapperFor(Class configBeanType) { - return (Optional) INSTANCE.get(); + public static Optional configBeanMapperFor(Class configBeanType) { + return INSTANCE.get(); } - private static Optional> load() { + private static Optional load() { Optional provider = HelidonServiceLoader .create(ServiceLoader.load(ConfigBeanMapperProvider.class, ConfigBeanMapperProvider.class.getClassLoader())) .asList() diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java index 2c6b65cde3d..d4faef6026e 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperProvider.java @@ -29,6 +29,6 @@ public interface ConfigBeanMapperProvider { * * @return the global config bean mapper instance */ - ConfigBeanMapper configBeanMapper(); + ConfigBeanMapper configBeanMapper(); } diff --git a/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigProvider.java similarity index 52% rename from common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java rename to pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigProvider.java index df73647af6e..03178d8df85 100644 --- a/common/config/src/main/java/io/helidon/common/config/spi/ConfigProvider.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigProvider.java @@ -14,23 +14,31 @@ * limitations under the License. */ -package io.helidon.common.config.spi; +package io.helidon.pico.builder.config.spi; import java.util.Optional; import io.helidon.common.config.Config; /** - * Java {@link java.util.ServiceLoader} provider interface for delivering the {@link io.helidon.common.config.Config} instance. - * - * @see io.helidon.common.config.ConfigHolder + * Generated {@link io.helidon.pico.builder.config.ConfigBean}-annotated types and the associated builder types implement + * this contract. + */ +@FunctionalInterface +public interface ConfigProvider /* extends Supplier*/ { +/* + Important Note: caution should be exercised to avoid any 0-arg or 1-arg method. This is because it might clash with generated + methods. If its necessary to have a 0 or 1-arg method then the convention of prefixing the method with two underscores should be + used. + + Conceptually this is the same as {@code Supplier}. However, the get() method imposed by supplier may + clash with generated code */ -public interface ConfigProvider { /** - * The service-loaded global {@link io.helidon.common.config.Config} instance. + * Optionally provides a configuration instance. * - * @return the global config instance + * @return the optional configuration */ // note that this needs to have double underscore since it is available in generated code Optional __config(); diff --git a/pico/builder-config/builder-config/src/main/java/module-info.java b/pico/builder-config/builder-config/src/main/java/module-info.java index 8eb222c048a..daa15767c12 100644 --- a/pico/builder-config/builder-config/src/main/java/module-info.java +++ b/pico/builder-config/builder-config/src/main/java/module-info.java @@ -24,6 +24,7 @@ requires io.helidon.common.config; uses io.helidon.pico.builder.config.spi.ConfigBeanMapperProvider; + uses io.helidon.pico.builder.config.spi.ConfigProvider; uses io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidatorProvider; uses io.helidon.pico.builder.config.spi.ConfigResolverProvider; uses io.helidon.pico.builder.config.spi.StringValueParserProvider; diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java index 398effc3804..de49064213e 100644 --- a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java @@ -38,12 +38,12 @@ import io.helidon.pico.Contract; import io.helidon.pico.ExternalContracts; import io.helidon.pico.builder.config.ConfigBean; +import io.helidon.pico.builder.config.spi.ConfigBeanBase; +import io.helidon.pico.builder.config.spi.ConfigBeanBuilderBase; import io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidator; import io.helidon.pico.builder.config.spi.ConfigBeanInfo; import io.helidon.pico.builder.config.spi.ConfigResolver; import io.helidon.pico.builder.config.spi.DefaultConfigResolverRequest; -import io.helidon.pico.builder.config.spi.GeneratedConfigBeanBase; -import io.helidon.pico.builder.config.spi.GeneratedConfigBeanBuilderBase; import io.helidon.pico.builder.config.spi.MetaConfigBeanInfo; import io.helidon.pico.builder.config.spi.ResolutionCtx; import io.helidon.pico.types.AnnotationAndValue; @@ -56,8 +56,8 @@ * A specialization of {@link DefaultBuilderCreator} that supports the additional add-ons to the builder generated classes that * binds to the config sub-system. * - * @see io.helidon.pico.builder.config.spi.GeneratedConfigBean - * @see io.helidon.pico.builder.config.spi.GeneratedConfigBeanBuilder + * @see io.helidon.pico.builder.config.spi.ConfigBean + * @see io.helidon.pico.builder.config.spi.ConfigBeanBuilder */ @Weight(Weighted.DEFAULT_WEIGHT) public class ConfigBeanBuilderCreator extends DefaultBuilderCreator { @@ -89,12 +89,12 @@ protected void preValidate(TypeName implTypeName, @Override protected Optional baseExtendsTypeName(BodyContext ctx) { - return Optional.of(DefaultTypeName.create(GeneratedConfigBeanBase.class)); + return Optional.of(DefaultTypeName.create(ConfigBeanBase.class)); } @Override protected Optional baseExtendsBuilderTypeName(BodyContext ctx) { - return Optional.of(DefaultTypeName.create(GeneratedConfigBeanBuilderBase.class)); + return Optional.of(DefaultTypeName.create(ConfigBeanBuilderBase.class)); } @Override From 3bd66facf43e24a9b9d2a238370e8db2209cbdc5 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 29 Nov 2022 17:02:40 -0500 Subject: [PATCH 31/36] checkstyles --- .../src/main/java/io/helidon/config/spi/ConfigMapper.java | 2 +- .../java/io/helidon/config/spi/ConfigMapperProvider.java | 2 +- etc/checkstyle-suppressions.xml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java index b4c3a263c79..5041798c717 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * 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. diff --git a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java index 86f8d140cef..e1c1677c8e7 100644 --- a/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java +++ b/config/config/src/main/java/io/helidon/config/spi/ConfigMapperProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. + * Copyright (c) 2017, 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. diff --git a/etc/checkstyle-suppressions.xml b/etc/checkstyle-suppressions.xml index b4f66729bb0..9bbc1e0d4a7 100644 --- a/etc/checkstyle-suppressions.xml +++ b/etc/checkstyle-suppressions.xml @@ -80,11 +80,11 @@ - - - From 2dda9eceb58ee323b86f176c84ab5b37cb406fcc Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Tue, 29 Nov 2022 17:17:57 -0500 Subject: [PATCH 32/36] more checkstyles --- etc/checkstyle-suppressions.xml | 2 +- .../io/helidon/pico/builder/config/spi/ConfigBeanCommon.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/checkstyle-suppressions.xml b/etc/checkstyle-suppressions.xml index 9bbc1e0d4a7..5480f22d5bf 100644 --- a/etc/checkstyle-suppressions.xml +++ b/etc/checkstyle-suppressions.xml @@ -84,7 +84,7 @@ checks="MethodName"/> - diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java index 580c10ccee6..5a3f3a68958 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java @@ -44,7 +44,7 @@ public interface ConfigBeanCommon extends ConfigProvider { Optional __config(); /** - * Returns the {@link io.helidon.pico.builder.config.ConfigBean}-annotated type, + * Returns the {@link io.helidon.pico.builder.config.ConfigBean}-annotated type. * * @return the config bean type */ From c355b7abd1b457eac436186098604e405fd72938 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 1 Dec 2022 01:29:50 +0100 Subject: [PATCH 33/36] Changes to builder modules --- .../io/helidon/builder/AttributeVisitor.java | 6 ++-- .../{spi => }/RequiredAttributeVisitor.java | 4 +-- .../io/helidon/builder/spi/package-info.java | 20 ------------ .../builder/src/main/java/module-info.java | 3 +- ...eator.java => BuilderCreatorProvider.java} | 4 ++- ...ator.java => TypeInfoCreatorProvider.java} | 4 ++- .../builder/processor/spi/package-info.java | 8 ++--- .../builder/processor/tools/BodyContext.java | 16 +++++----- .../processor/tools/BuilderTypeTools.java | 6 ++-- ...ava => DefaultBuilderCreatorProvider.java} | 12 +++---- .../tools/GenerateVisitorSupport.java | 7 ++-- .../src/main/java/module-info.java | 6 ++-- .../builder/processor/BuilderProcessor.java | 32 +++++++++---------- .../processor/src/main/java/module-info.java | 4 +-- .../spi/ConfigBeanBuilderValidator.java | 2 +- .../builder/config/spi/ConfigBeanCommon.java | 8 ++--- .../tools/ConfigBeanBuilderCreator.java | 6 ++-- .../processor/src/main/java/module-info.java | 6 ++-- .../tests/ConfigBeanBuilderCreatorTest.java | 4 +-- 19 files changed, 73 insertions(+), 85 deletions(-) rename builder/builder/src/main/java/io/helidon/builder/{spi => }/RequiredAttributeVisitor.java (98%) delete mode 100644 builder/builder/src/main/java/io/helidon/builder/spi/package-info.java rename builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/{BuilderCreator.java => BuilderCreatorProvider.java} (95%) rename builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/{TypeInfoCreator.java => TypeInfoCreatorProvider.java} (92%) rename builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/{DefaultBuilderCreator.java => DefaultBuilderCreatorProvider.java} (99%) diff --git a/builder/builder/src/main/java/io/helidon/builder/AttributeVisitor.java b/builder/builder/src/main/java/io/helidon/builder/AttributeVisitor.java index 8ba1954f710..91e0d9d7433 100644 --- a/builder/builder/src/main/java/io/helidon/builder/AttributeVisitor.java +++ b/builder/builder/src/main/java/io/helidon/builder/AttributeVisitor.java @@ -23,9 +23,11 @@ * A functional interface that can be used to visit all attributes of this type. *

      * This type is used when {@link Builder#requireLibraryDependencies()} is used. + * + * @param type of the user defined context this attribute visitor supports */ @FunctionalInterface -public interface AttributeVisitor { +public interface AttributeVisitor { /** * Visits the attribute named 'attrName'. @@ -40,7 +42,7 @@ public interface AttributeVisitor { void visit(String attrName, Supplier valueSupplier, Map meta, - Object userDefinedCtx, + T userDefinedCtx, Class type, Class... typeArgument); diff --git a/builder/builder/src/main/java/io/helidon/builder/spi/RequiredAttributeVisitor.java b/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java similarity index 98% rename from builder/builder/src/main/java/io/helidon/builder/spi/RequiredAttributeVisitor.java rename to builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java index 96d2a0e5c82..22f627697ce 100644 --- a/builder/builder/src/main/java/io/helidon/builder/spi/RequiredAttributeVisitor.java +++ b/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.builder.spi; +package io.helidon.builder; import java.util.ArrayList; import java.util.List; @@ -38,7 +38,7 @@ * code generated sources that Helidon generates. */ @Deprecated -public class RequiredAttributeVisitor implements AttributeVisitor { +public class RequiredAttributeVisitor implements AttributeVisitor { private final List errors = new ArrayList<>(); /** diff --git a/builder/builder/src/main/java/io/helidon/builder/spi/package-info.java b/builder/builder/src/main/java/io/helidon/builder/spi/package-info.java deleted file mode 100644 index 2f58fa53351..00000000000 --- a/builder/builder/src/main/java/io/helidon/builder/spi/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. - */ - -/** - * Builder runtime tooling SPI. - */ -package io.helidon.builder.spi; diff --git a/builder/builder/src/main/java/module-info.java b/builder/builder/src/main/java/module-info.java index 6498d686e81..13f8575e737 100644 --- a/builder/builder/src/main/java/module-info.java +++ b/builder/builder/src/main/java/module-info.java @@ -15,9 +15,8 @@ */ /** - * The Builder API / SPI module. + * The Builder API module. */ module io.helidon.builder { exports io.helidon.builder; - exports io.helidon.builder.spi; } diff --git a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreator.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreatorProvider.java similarity index 95% rename from builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreator.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreatorProvider.java index 520209c1eb7..e7e3c8f4f67 100644 --- a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreator.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/BuilderCreatorProvider.java @@ -23,12 +23,14 @@ import io.helidon.pico.types.AnnotationAndValue; /** + * Java {@link java.util.ServiceLoader} provider interface used to discover builder creators. + *

      * Implementors of this contract will be called to process {@link io.helidon.builder.BuilderTrigger}-annotated * annotation types that they know how to handle. This is based upon the {@link #supportedAnnotationTypes()} as well as the * {@link io.helidon.common.Weight} * assigned to the implementation class implementing this interface. */ -public interface BuilderCreator { +public interface BuilderCreatorProvider { /** * The set of {@link io.helidon.builder.Builder}-like annotations that this creator knows how to handle. Note that diff --git a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreator.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreatorProvider.java similarity index 92% rename from builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreator.java rename to builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreatorProvider.java index 5a04564b4f0..b6902144b89 100644 --- a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreator.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/TypeInfoCreatorProvider.java @@ -25,9 +25,11 @@ import io.helidon.pico.types.TypeName; /** + * Java {@link java.util.ServiceLoader} provider interface used to discover type info creators. + *

      * Used to create a {@link TypeInfo} from the provided arguments. */ -public interface TypeInfoCreator { +public interface TypeInfoCreatorProvider { /** * Creates a {@link TypeInfo}. diff --git a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java index 11a24ddee05..c8d75d6a9e9 100644 --- a/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java +++ b/builder/processor-spi/src/main/java/io/helidon/builder/processor/spi/package-info.java @@ -17,10 +17,10 @@ /** * The Pico Builder Processor SPI module provides these definitions: *

        - *
      1. {@link io.helidon.builder.processor.spi.BuilderCreator} - responsible for code generating the implementation w/ - * a fluent builder.
      2. - *
      3. {@link io.helidon.builder.processor.spi.TypeInfoCreator} - responsible for code generating the model object for - * the target interface.
      4. + *
      5. {@link io.helidon.builder.processor.spi.BuilderCreatorProvider} - responsible for code generating the + * implementation w/ a fluent builder.
      6. + *
      7. {@link io.helidon.builder.processor.spi.TypeInfoCreatorProvider} - responsible for code generating the model + * object for the target interface.
      8. *
      9. {@link io.helidon.builder.processor.spi.TypeAndBody} - the dom-like description of the target type of the * builder.
      10. *
      diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java index 7c279ebe57c..577f26760f8 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java @@ -31,14 +31,14 @@ import io.helidon.pico.types.TypeName; import io.helidon.pico.types.TypedElementName; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.BUILDER_ANNO_TYPE_NAME; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_INCLUDE_META_ATTRIBUTES; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_LIST_TYPE; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_MAP_TYPE; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.DEFAULT_SET_TYPE; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.SUPPORT_STREAMS_ON_BUILDER; -import static io.helidon.builder.processor.tools.DefaultBuilderCreator.SUPPORT_STREAMS_ON_IMPL; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.BUILDER_ANNO_TYPE_NAME; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_INCLUDE_META_ATTRIBUTES; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_LIST_TYPE; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_MAP_TYPE; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_SET_TYPE; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.SUPPORT_STREAMS_ON_BUILDER; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.SUPPORT_STREAMS_ON_IMPL; /** * Represents the context of the body being code generated. diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java index 3542de520b4..7c4a000f561 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BuilderTypeTools.java @@ -46,7 +46,7 @@ import io.helidon.builder.processor.spi.DefaultTypeInfo; import io.helidon.builder.processor.spi.TypeInfo; -import io.helidon.builder.processor.spi.TypeInfoCreator; +import io.helidon.builder.processor.spi.TypeInfoCreatorProvider; import io.helidon.common.Weight; import io.helidon.common.Weighted; import io.helidon.pico.types.AnnotationAndValue; @@ -57,11 +57,11 @@ import io.helidon.pico.types.TypedElementName; /** - * The default implementation for {@link io.helidon.builder.processor.spi.TypeInfoCreator}. This also contains an abundance of + * The default implementation for {@link io.helidon.builder.processor.spi.TypeInfoCreatorProvider}. This also contains an abundance of * other useful methods used for annotation processing. */ @Weight(Weighted.DEFAULT_WEIGHT - 1) -public class BuilderTypeTools implements TypeInfoCreator { +public class BuilderTypeTools implements TypeInfoCreatorProvider { /** * Default constructor. diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java similarity index 99% rename from builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java rename to builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java index 78a80c0967f..4c80fef0d8c 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreator.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java @@ -34,11 +34,11 @@ import io.helidon.builder.AttributeVisitor; import io.helidon.builder.Builder; import io.helidon.builder.Singular; -import io.helidon.builder.processor.spi.BuilderCreator; +import io.helidon.builder.processor.spi.BuilderCreatorProvider; import io.helidon.builder.processor.spi.DefaultTypeAndBody; import io.helidon.builder.processor.spi.TypeAndBody; import io.helidon.builder.processor.spi.TypeInfo; -import io.helidon.builder.spi.RequiredAttributeVisitor; +import io.helidon.builder.RequiredAttributeVisitor; import io.helidon.common.Weight; import io.helidon.common.Weighted; import io.helidon.config.metadata.ConfiguredOption; @@ -52,10 +52,10 @@ import static io.helidon.builder.processor.tools.BodyContext.toBeanAttributeName; /** - * Default implementation for {@link BuilderCreator}. + * Default implementation for {@link io.helidon.builder.processor.spi.BuilderCreatorProvider}. */ @Weight(Weighted.DEFAULT_WEIGHT - 1) // allow all other creators to take precedence over us... -public class DefaultBuilderCreator implements BuilderCreator { +public class DefaultBuilderCreatorProvider implements BuilderCreatorProvider { static final boolean DEFAULT_INCLUDE_META_ATTRIBUTES = true; static final boolean DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES = true; static final String DEFAULT_IMPL_PREFIX = Builder.DEFAULT_IMPL_PREFIX; @@ -73,7 +73,7 @@ public class DefaultBuilderCreator implements BuilderCreator { */ // note: this needs to remain public since it will be resolved via service loader ... @Deprecated - public DefaultBuilderCreator() { + public DefaultBuilderCreatorProvider() { } @Override @@ -525,7 +525,7 @@ protected void appendVisitAttributes(StringBuilder builder, } else { GenerateJavadoc.visitAttributes(builder, ctx, extraTabs); } - builder.append(extraTabs).append("\tpublic void visitAttributes(AttributeVisitor visitor, Object userDefinedCtx) {\n"); + builder.append(extraTabs).append("\tpublic void visitAttributes(AttributeVisitor visitor, T userDefinedCtx) {\n"); if (ctx.hasParent()) { builder.append(extraTabs).append("\t\tsuper.visitAttributes(visitor, userDefinedCtx);\n"); } diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java index 0dd14e5f42d..72b7d1b32fc 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java @@ -31,9 +31,10 @@ static void appendExtraInnerClasses(StringBuilder builder, && !ctx.requireLibraryDependencies()) { builder.append("\n\n\t/**\n" + "\t * A functional interface that can be used to visit all attributes of this type.\n" + + "\t * @param type of user defined context" + "\t */\n"); builder.append("\t@FunctionalInterface\n" - + "\tpublic static interface AttributeVisitor {\n" + + "\tpublic static interface AttributeVisitor {\n" + "\t\t/**\n" + "\t\t * Visits the attribute named 'attrName'.\n" + "\t\t *\n" @@ -47,7 +48,7 @@ static void appendExtraInnerClasses(StringBuilder builder, + "type)\n" + "\t\t */\n" + "\t\tvoid visit(String attrName, Supplier valueSupplier, " - + "Map meta, Object userDefinedCtx, Class " + + "Map meta, T userDefinedCtx, Class " + "type, Class... typeArgument);\n" + "\t}"); @@ -57,7 +58,7 @@ static void appendExtraInnerClasses(StringBuilder builder, + "\t * must be annotated with {@code ConfiguredOption(required=true)} for this to be " + "enforced.\n" + "\t */\n"); - builder.append("\tprotected static class RequiredAttributeVisitor implements AttributeVisitor {\n" + builder.append("\tprotected static class RequiredAttributeVisitor implements AttributeVisitor {\n" + "\t\tprivate final List errors = new java.util.ArrayList();\n" + "\n" + "\t\t/**\n" diff --git a/builder/processor-tools/src/main/java/module-info.java b/builder/processor-tools/src/main/java/module-info.java index 14b7be124cf..39041e73c44 100644 --- a/builder/processor-tools/src/main/java/module-info.java +++ b/builder/processor-tools/src/main/java/module-info.java @@ -27,8 +27,8 @@ exports io.helidon.builder.processor.tools; - provides io.helidon.builder.processor.spi.BuilderCreator - with io.helidon.builder.processor.tools.DefaultBuilderCreator; - provides io.helidon.builder.processor.spi.TypeInfoCreator + provides io.helidon.builder.processor.spi.BuilderCreatorProvider + with io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider; + provides io.helidon.builder.processor.spi.TypeInfoCreatorProvider with io.helidon.builder.processor.tools.BuilderTypeTools; } diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/BuilderProcessor.java b/builder/processor/src/main/java/io/helidon/builder/processor/BuilderProcessor.java index 0118a4054b7..d1a67b8891b 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/BuilderProcessor.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/BuilderProcessor.java @@ -39,10 +39,10 @@ import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import io.helidon.builder.processor.spi.BuilderCreator; +import io.helidon.builder.processor.spi.BuilderCreatorProvider; import io.helidon.builder.processor.spi.TypeAndBody; import io.helidon.builder.processor.spi.TypeInfo; -import io.helidon.builder.processor.spi.TypeInfoCreator; +import io.helidon.builder.processor.spi.TypeInfoCreatorProvider; import io.helidon.builder.processor.tools.BuilderTypeTools; import io.helidon.common.HelidonServiceLoader; import io.helidon.common.Weights; @@ -55,13 +55,13 @@ */ public class BuilderProcessor extends AbstractProcessor { private static final System.Logger LOGGER = System.getLogger(BuilderProcessor.class.getName()); - private static final Map> PRODUCERS_BY_ANNOTATION = new LinkedHashMap<>(); + private static final Map> PRODUCERS_BY_ANNOTATION = new LinkedHashMap<>(); private static final Set> ALL_ANNO_TYPES_HANDLED = new LinkedHashSet<>(); - private static final List PRODUCERS = initialize(); + private static final List PRODUCERS = initialize(); private final LinkedHashSet elementsProcessed = new LinkedHashSet<>(); - private TypeInfoCreator tools; + private TypeInfoCreatorProvider tools; private Elements elementUtils; /** @@ -87,25 +87,25 @@ public void init(ProcessingEnvironment processingEnv) { this.elementUtils = processingEnv.getElementUtils(); this.tools = HelidonServiceLoader.create( - ServiceLoader.load(TypeInfoCreator.class, TypeInfoCreator.class.getClassLoader())) + ServiceLoader.load(TypeInfoCreatorProvider.class, TypeInfoCreatorProvider.class.getClassLoader())) .asList() .stream() .findFirst() .orElse(null); if (tools == null) { - String msg = "no available " + TypeInfoCreator.class.getSimpleName() + " instances found"; + String msg = "no available " + TypeInfoCreatorProvider.class.getSimpleName() + " instances found"; processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg); throw new IllegalStateException(msg); } - LOGGER.log(System.Logger.Level.DEBUG, TypeInfoCreator.class.getSimpleName() + ": " + tools); + LOGGER.log(System.Logger.Level.DEBUG, TypeInfoCreatorProvider.class.getSimpleName() + ": " + tools); if (PRODUCERS.isEmpty()) { - String msg = "no available " + BuilderCreator.class.getSimpleName() + " instances found"; + String msg = "no available " + BuilderCreatorProvider.class.getSimpleName() + " instances found"; processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg); throw new IllegalStateException(msg); } - LOGGER.log(System.Logger.Level.DEBUG, BuilderCreator.class.getSimpleName() + "s: " + PRODUCERS); + LOGGER.log(System.Logger.Level.DEBUG, BuilderCreatorProvider.class.getSimpleName() + "s: " + PRODUCERS); } @Override @@ -163,7 +163,7 @@ protected void process(Class annoType, Element element) th return; } - Set creators = getProducersForType(DefaultTypeName.create(annoType)); + Set creators = getProducersForType(DefaultTypeName.create(annoType)); Optional> result = creators.stream() .map(it -> it.create(typeInfo.get(), builderAnnotation)) .filter(it -> !it.isEmpty()) @@ -192,11 +192,11 @@ protected void codegen(List codegens) throws IOException { } } - private static List initialize() { + private static List initialize() { try { // note: it is important to use this class' CL since maven will not give us the "right" one. - List producers = HelidonServiceLoader - .create(ServiceLoader.load(BuilderCreator.class, BuilderCreator.class.getClassLoader())) + List producers = HelidonServiceLoader + .create(ServiceLoader.load(BuilderCreatorProvider.class, BuilderCreatorProvider.class.getClassLoader())) .asList(); producers.forEach(producer -> { producer.supportedAnnotationTypes().forEach(annoType -> { @@ -214,8 +214,8 @@ private static List initialize() { } } - private Set getProducersForType(TypeName annoTypeName) { - Set set = PRODUCERS_BY_ANNOTATION.get(annoTypeName); + private Set getProducersForType(TypeName annoTypeName) { + Set set = PRODUCERS_BY_ANNOTATION.get(annoTypeName); return set == null ? Set.of() : Set.copyOf(set); } diff --git a/builder/processor/src/main/java/module-info.java b/builder/processor/src/main/java/module-info.java index e1b0e329bd7..530a9243547 100644 --- a/builder/processor/src/main/java/module-info.java +++ b/builder/processor/src/main/java/module-info.java @@ -30,6 +30,6 @@ provides javax.annotation.processing.Processor with io.helidon.builder.processor.BuilderProcessor; - uses io.helidon.builder.processor.spi.BuilderCreator; - uses io.helidon.builder.processor.spi.TypeInfoCreator; + uses io.helidon.builder.processor.spi.BuilderCreatorProvider; + uses io.helidon.builder.processor.spi.TypeInfoCreatorProvider; } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java index 7f6c6c372d5..e8b64253edc 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderValidator.java @@ -66,7 +66,7 @@ enum Severity { * Represents a single round of validation. A single round of validation will iterate over each attributes of the * config bean, calling {@link #validate(String, Supplier, Class, java.util.Map)} for each attribute. */ - interface ValidationRound extends AttributeVisitor { + interface ValidationRound extends AttributeVisitor { /** * All the issues found. diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java index 5a3f3a68958..74d20c7349d 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java @@ -53,10 +53,10 @@ public interface ConfigBeanCommon extends ConfigProvider { /** * Visits all attributes with the provided {@link io.helidon.builder.AttributeVisitor}. * - * @param visitor the visitor - * @param userDefinedCtx any user-defined context + * @param visitor the visitor + * @param userDefinedCtx any user-defined context */ - void visitAttributes(AttributeVisitor visitor, - Object userDefinedCtx); + void visitAttributes(AttributeVisitor visitor, + T userDefinedCtx); } diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java index de49064213e..99b436f007b 100644 --- a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java @@ -30,7 +30,7 @@ import io.helidon.builder.processor.spi.TypeInfo; import io.helidon.builder.processor.tools.BodyContext; -import io.helidon.builder.processor.tools.DefaultBuilderCreator; +import io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider; import io.helidon.common.Weight; import io.helidon.common.Weighted; import io.helidon.common.config.Config; @@ -53,14 +53,14 @@ import io.helidon.pico.types.TypedElementName; /** - * A specialization of {@link DefaultBuilderCreator} that supports the additional add-ons to the builder generated classes that + * A specialization of {@link io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider} that supports the additional add-ons to the builder generated classes that * binds to the config sub-system. * * @see io.helidon.pico.builder.config.spi.ConfigBean * @see io.helidon.pico.builder.config.spi.ConfigBeanBuilder */ @Weight(Weighted.DEFAULT_WEIGHT) -public class ConfigBeanBuilderCreator extends DefaultBuilderCreator { +public class ConfigBeanBuilderCreator extends DefaultBuilderCreatorProvider { /** * Default constructor. diff --git a/pico/builder-config/processor/src/main/java/module-info.java b/pico/builder-config/processor/src/main/java/module-info.java index 5d740b78532..54eee4f378e 100644 --- a/pico/builder-config/processor/src/main/java/module-info.java +++ b/pico/builder-config/processor/src/main/java/module-info.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import io.helidon.builder.processor.spi.BuilderCreatorProvider; + /** * Helidon Pico ConfigBean Builder Processor (Tools) module. */ @@ -31,8 +33,8 @@ exports io.helidon.pico.builder.config.processor.tools; - uses io.helidon.builder.processor.spi.BuilderCreator; + uses BuilderCreatorProvider; - provides io.helidon.builder.processor.spi.BuilderCreator + provides BuilderCreatorProvider with io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; } diff --git a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java index 68607bec862..ba38cfccf99 100644 --- a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java +++ b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java @@ -18,7 +18,7 @@ import io.helidon.pico.builder.config.ConfigBean; import io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; -import io.helidon.builder.processor.spi.BuilderCreator; +import io.helidon.builder.processor.spi.BuilderCreatorProvider; import org.junit.jupiter.api.Test; @@ -29,7 +29,7 @@ class ConfigBeanBuilderCreatorTest { @Test void supportedAnnotationTypes() { - BuilderCreator creator = new ConfigBeanBuilderCreator(); + BuilderCreatorProvider creator = new ConfigBeanBuilderCreator(); assertEquals(1, creator.supportedAnnotationTypes().size()); assertSame(ConfigBean.class, creator.supportedAnnotationTypes().iterator().next()); } From b0f7758ce04ba04f79ec12f2a6ca9188397f144d Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 1 Dec 2022 02:08:03 +0100 Subject: [PATCH 34/36] Changes to config beans and build fixes. --- .../builder/RequiredAttributeVisitor.java | 2 - .../tools/DefaultBuilderCreatorProvider.java | 2 +- .../processor/tools/GenerateJavadoc.java | 1 + .../etc/spotbugs/checkstyle-suppressions.xml | 26 ------------- .../builder-config/etc/spotbugs/exclude.xml | 39 ------------------- pico/builder-config/builder-config/pom.xml | 6 --- .../config/spi/ConfigBeanBuilderBase.java | 12 +++--- .../builder/config/spi/ConfigBeanCommon.java | 1 + .../config/spi/ConfigBeanMapperHolder.java | 12 ++---- .../builder/config/spi/ConfigResolver.java | 6 +-- .../config/spi/ConfigResolverHolder.java | 10 ++--- .../config/spi/DefaultConfigResolver.java | 10 ++--- ...olutionCtx.java => ResolutionContext.java} | 22 +++++------ .../config/spi/StringValueParserHolder.java | 10 ++--- .../src/main/java/module-info.java | 1 - .../{tools => }/ConfigBeanBuilderCreator.java | 10 +++-- .../processor/{tools => }/package-info.java | 2 +- .../processor/src/main/java/module-info.java | 10 ++--- .../tests/ConfigBeanBuilderCreatorTest.java | 2 +- 19 files changed, 48 insertions(+), 136 deletions(-) delete mode 100644 pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml delete mode 100644 pico/builder-config/builder-config/etc/spotbugs/exclude.xml rename pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/{ResolutionCtx.java => ResolutionContext.java} (88%) rename pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/{tools => }/ConfigBeanBuilderCreator.java (98%) rename pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/{tools => }/package-info.java (92%) diff --git a/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java b/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java index 22f627697ce..cb8884f7a9a 100644 --- a/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java +++ b/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java @@ -22,8 +22,6 @@ import java.util.Objects; import java.util.function.Supplier; -import io.helidon.builder.AttributeVisitor; - /** * An implementation of {@link AttributeVisitor} that will validate each attribute to enforce not-null in accordance with * {@link io.helidon.config.metadata.ConfiguredOption#required()}. diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java index 4c80fef0d8c..4a1daff044d 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java @@ -33,12 +33,12 @@ import io.helidon.builder.Annotated; import io.helidon.builder.AttributeVisitor; import io.helidon.builder.Builder; +import io.helidon.builder.RequiredAttributeVisitor; import io.helidon.builder.Singular; import io.helidon.builder.processor.spi.BuilderCreatorProvider; import io.helidon.builder.processor.spi.DefaultTypeAndBody; import io.helidon.builder.processor.spi.TypeAndBody; import io.helidon.builder.processor.spi.TypeInfo; -import io.helidon.builder.RequiredAttributeVisitor; import io.helidon.common.Weight; import io.helidon.common.Weighted; import io.helidon.config.metadata.ConfiguredOption; diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateJavadoc.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateJavadoc.java index 2168b8535ed..29b400ad841 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateJavadoc.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateJavadoc.java @@ -169,6 +169,7 @@ static void visitAttributes(StringBuilder builder, builder.append(extraTabs).append("\t *\n"); builder.append(extraTabs).append("\t * @param visitor\t\t\tthe visitor called for each attribute\n"); builder.append(extraTabs).append("\t * @param userDefinedCtx\tany object you wish to pass to each visit call\n"); + builder.append(extraTabs).append("\t * @param type of the user defined context\n"); builder.append(extraTabs).append("\t */\n"); } } diff --git a/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml b/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml deleted file mode 100644 index 4b9dc6e150d..00000000000 --- a/pico/builder-config/builder-config/etc/spotbugs/checkstyle-suppressions.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - diff --git a/pico/builder-config/builder-config/etc/spotbugs/exclude.xml b/pico/builder-config/builder-config/etc/spotbugs/exclude.xml deleted file mode 100644 index e8153d5c645..00000000000 --- a/pico/builder-config/builder-config/etc/spotbugs/exclude.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/pico/builder-config/builder-config/pom.xml b/pico/builder-config/builder-config/pom.xml index a931c08bfe8..5fd2c91acb5 100644 --- a/pico/builder-config/builder-config/pom.xml +++ b/pico/builder-config/builder-config/pom.xml @@ -32,12 +32,6 @@ Helidon Pico Config Builder API / SPI - - true - - - - io.helidon.builder diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java index 700f1240c74..527ceea0310 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java @@ -53,12 +53,12 @@ public void acceptConfig(Config cfg, * @param validator the config bean builder validator * @return the resolution context */ - protected ResolutionCtx createResolutionContext(Class configBeanType, - Config cfg, - ConfigResolver resolver, - ConfigBeanBuilderValidator validator) { + protected ResolutionContext createResolutionContext(Class configBeanType, + Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator) { // note to self: that in the future we should probably accept a code-generated 'version id' here --jtrent - return ResolutionCtx.create(configBeanType, cfg, resolver, validator); + return ResolutionContext.create(configBeanType, cfg, resolver, validator); } /** @@ -66,7 +66,7 @@ protected ResolutionCtx createResolutionContext(Class configBeanType, * * @param ctx the resolution context */ - protected void finishedResolution(ResolutionCtx ctx) { + protected void finishedResolution(ResolutionContext ctx) { // note to self: need to add validation here --jtrent } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java index 74d20c7349d..8c589020b27 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanCommon.java @@ -55,6 +55,7 @@ public interface ConfigBeanCommon extends ConfigProvider { * * @param visitor the visitor * @param userDefinedCtx any user-defined context + * @param type of the user defined context */ void visitAttributes(AttributeVisitor visitor, T userDefinedCtx); diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java index 03627556c63..440baf0c5c1 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanMapperHolder.java @@ -44,22 +44,16 @@ private ConfigBeanMapperHolder() { * @param configBeanType the config bean type to map * @return the config bean mapper */ - @SuppressWarnings({"rawTypes", "unchecked"}) public static Optional configBeanMapperFor(Class configBeanType) { return INSTANCE.get(); } private static Optional load() { - Optional provider = HelidonServiceLoader + return HelidonServiceLoader .create(ServiceLoader.load(ConfigBeanMapperProvider.class, ConfigBeanMapperProvider.class.getClassLoader())) .asList() .stream() - .findFirst(); - if (provider.isEmpty()) { - return Optional.empty(); - } - - return Optional.of(provider.get().configBeanMapper()); + .findFirst() + .map(ConfigBeanMapperProvider::configBeanMapper); } - } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java index bd9d0fd9b81..2731c257041 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolver.java @@ -35,7 +35,7 @@ public interface ConfigResolver { * @param the attribute value type being resolved in the request * @return the resolved value or empty if unable to resolve the request */ - Optional of(ResolutionCtx ctx, + Optional of(ResolutionContext ctx, Map> meta, ConfigResolverRequest request); @@ -49,7 +49,7 @@ Optional of(ResolutionCtx ctx, * @param the attribute value type being resolved in the request * @return the resolved value or empty if unable to resolve the request */ - Optional> ofCollection(ResolutionCtx ctx, + Optional> ofCollection(ResolutionContext ctx, Map> meta, ConfigResolverRequest request); @@ -64,7 +64,7 @@ Optional> ofCollection(ResolutionCtx ctx, * @param the map attribute value type being resolved in the request * @return the resolved value or empty if unable to resolve the request */ - Optional> ofMap(ResolutionCtx ctx, + Optional> ofMap(ResolutionContext ctx, Map> meta, ConfigResolverMapRequest request); diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java index d71ec21bd0a..fa456d70696 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigResolverHolder.java @@ -43,16 +43,12 @@ public static Optional configResolver() { } private static Optional load() { - Optional provider = HelidonServiceLoader + return HelidonServiceLoader .create(ServiceLoader.load(ConfigResolverProvider.class, ConfigResolverProvider.class.getClassLoader())) .asList() .stream() - .findFirst(); - if (provider.isEmpty()) { - return Optional.empty(); - } - - return Optional.of(provider.get().configResolver()); + .findFirst() + .map(ConfigResolverProvider::configResolver); } } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java index f2841c03157..6fbe11c79d2 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/DefaultConfigResolver.java @@ -52,7 +52,7 @@ public ConfigResolver configResolver() { } @Override - public Optional of(ResolutionCtx ctx, + public Optional of(ResolutionContext ctx, Map> meta, ConfigResolverRequest request) { Config attrCfg = ctx.config().get(request.configKey()); @@ -62,9 +62,9 @@ public Optional of(ResolutionCtx ctx, @Override @SuppressWarnings("unchecked") - public Optional> ofCollection(ResolutionCtx ctx, - Map> meta, - ConfigResolverRequest request) { + public Optional> ofCollection(ResolutionContext ctx, + Map> meta, + ConfigResolverRequest request) { Config attrCfg = ctx.config().get(request.configKey()); return attrCfg.exists() ? (Optional>) optionalWrappedConfig(attrCfg, meta, request) : Optional.empty(); @@ -72,7 +72,7 @@ public Optional> ofCollection(ResolutionCtx ctx, @Override @SuppressWarnings("unchecked") - public Optional> ofMap(ResolutionCtx ctx, + public Optional> ofMap(ResolutionContext ctx, Map> meta, ConfigResolverMapRequest request) { Config attrCfg = ctx.config().get(request.configKey()); diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionContext.java similarity index 88% rename from pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java rename to pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionContext.java index 618ef1a2290..515c75dc279 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionCtx.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ResolutionContext.java @@ -24,7 +24,7 @@ /** * Config resolution process context. */ -public class ResolutionCtx { +public class ResolutionContext { private final Class configBeanType; private final Config cfg; private final ConfigResolver resolver; @@ -35,7 +35,7 @@ public class ResolutionCtx { * * @param b the builder */ - protected ResolutionCtx(Builder b) { + protected ResolutionContext(Builder b) { this.configBeanType = Objects.requireNonNull(b.configBeanType); this.cfg = Objects.requireNonNull(b.cfg); this.resolver = Objects.requireNonNull(b.resolver); @@ -102,11 +102,11 @@ public static Builder builder() { * @param validator the bean builder validator * @return the resolution context */ - public static ResolutionCtx create(Class configBeanType, - Config cfg, - ConfigResolver resolver, - ConfigBeanBuilderValidator validator) { - return ResolutionCtx.builder() + public static ResolutionContext create(Class configBeanType, + Config cfg, + ConfigResolver resolver, + ConfigBeanBuilderValidator validator) { + return ResolutionContext.builder() .configBeanType(configBeanType) .config(cfg) .resolver(resolver) @@ -115,9 +115,9 @@ public static ResolutionCtx create(Class configBeanType, } /** - * Fluent builder for {@link io.helidon.pico.builder.config.spi.ResolutionCtx}. + * Fluent builder for {@link ResolutionContext}. */ - public static class Builder implements io.helidon.common.Builder { + public static class Builder implements io.helidon.common.Builder { private Class configBeanType; private Config cfg; private ConfigResolver resolver; @@ -135,8 +135,8 @@ protected Builder() { * @return the built instance */ @Override - public ResolutionCtx build() { - return new ResolutionCtx(this); + public ResolutionContext build() { + return new ResolutionContext(this); } /** diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java index 9c388f21e60..8ee0f8171f6 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/StringValueParserHolder.java @@ -43,16 +43,12 @@ public static Optional stringValueParser() { } private static Optional load() { - Optional provider = HelidonServiceLoader + return HelidonServiceLoader .create(ServiceLoader.load(StringValueParserProvider.class, StringValueParserProvider.class.getClassLoader())) .asList() .stream() - .findFirst(); - if (provider.isEmpty()) { - return Optional.empty(); - } - - return Optional.of(provider.get().stringValueParser()); + .findFirst() + .map(StringValueParserProvider::stringValueParser); } } diff --git a/pico/builder-config/builder-config/src/main/java/module-info.java b/pico/builder-config/builder-config/src/main/java/module-info.java index daa15767c12..8eb222c048a 100644 --- a/pico/builder-config/builder-config/src/main/java/module-info.java +++ b/pico/builder-config/builder-config/src/main/java/module-info.java @@ -24,7 +24,6 @@ requires io.helidon.common.config; uses io.helidon.pico.builder.config.spi.ConfigBeanMapperProvider; - uses io.helidon.pico.builder.config.spi.ConfigProvider; uses io.helidon.pico.builder.config.spi.ConfigBeanBuilderValidatorProvider; uses io.helidon.pico.builder.config.spi.ConfigResolverProvider; uses io.helidon.pico.builder.config.spi.StringValueParserProvider; diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/ConfigBeanBuilderCreator.java similarity index 98% rename from pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java rename to pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/ConfigBeanBuilderCreator.java index 99b436f007b..496e1c4951d 100644 --- a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/ConfigBeanBuilderCreator.java +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/ConfigBeanBuilderCreator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.pico.builder.config.processor.tools; +package io.helidon.pico.builder.config.processor; import java.lang.annotation.Annotation; import java.util.Collection; @@ -45,7 +45,7 @@ import io.helidon.pico.builder.config.spi.ConfigResolver; import io.helidon.pico.builder.config.spi.DefaultConfigResolverRequest; import io.helidon.pico.builder.config.spi.MetaConfigBeanInfo; -import io.helidon.pico.builder.config.spi.ResolutionCtx; +import io.helidon.pico.builder.config.spi.ResolutionContext; import io.helidon.pico.types.AnnotationAndValue; import io.helidon.pico.types.DefaultAnnotationAndValue; import io.helidon.pico.types.DefaultTypeName; @@ -205,7 +205,7 @@ protected void appendExtraBuilderMethods(StringBuilder builder, builder.append("\t\t@Override\n"); builder.append("\t\tpublic void acceptConfig" + "(Config cfg, ConfigResolver resolver, ConfigBeanBuilderValidator validator) {\n"); - builder.append("\t\t\t").append(ResolutionCtx.class.getName()) + builder.append("\t\t\t").append(ResolutionContext.class.getName()) .append(" ctx = createResolutionContext(__configBeanType(), cfg, resolver, validator);\n"); builder.append("\t\t\t__config(ctx.config());\n"); builder.append("\t\t\t__acceptAndResolve(ctx);\n"); @@ -219,7 +219,9 @@ protected void appendExtraBuilderMethods(StringBuilder builder, } else { javaDocAcceptResolveConfigCtx(builder, ctx, "ctx"); } - builder.append("\t\tprotected void __acceptAndResolve(").append(ResolutionCtx.class.getName()).append(" ctx) {\n"); + builder.append("\t\tprotected void __acceptAndResolve(") + .append(ResolutionContext.class.getName()) + .append(" ctx) {\n"); if (ctx.hasParent()) { builder.append("\t\t\tsuper.__acceptAndResolve(ctx);\n"); } diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/package-info.java similarity index 92% rename from pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java rename to pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/package-info.java index e6609e38653..afce940d43f 100644 --- a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/tools/package-info.java +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/package-info.java @@ -17,4 +17,4 @@ /** * Pico ConfigBean Processor extensions. */ -package io.helidon.pico.builder.config.processor.tools; +package io.helidon.pico.builder.config.processor; diff --git a/pico/builder-config/processor/src/main/java/module-info.java b/pico/builder-config/processor/src/main/java/module-info.java index 54eee4f378e..32bc81b9d04 100644 --- a/pico/builder-config/processor/src/main/java/module-info.java +++ b/pico/builder-config/processor/src/main/java/module-info.java @@ -14,8 +14,6 @@ * limitations under the License. */ -import io.helidon.builder.processor.spi.BuilderCreatorProvider; - /** * Helidon Pico ConfigBean Builder Processor (Tools) module. */ @@ -31,10 +29,8 @@ requires io.helidon.pico.types; requires io.helidon.pico; - exports io.helidon.pico.builder.config.processor.tools; - - uses BuilderCreatorProvider; + exports io.helidon.pico.builder.config.processor; - provides BuilderCreatorProvider - with io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; + provides io.helidon.builder.processor.spi.BuilderCreatorProvider + with io.helidon.pico.builder.config.processor.ConfigBeanBuilderCreator; } diff --git a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java index ba38cfccf99..1bcb0756c10 100644 --- a/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java +++ b/pico/builder-config/processor/src/test/java/io/helidon/pico/builder/config/tools/tests/ConfigBeanBuilderCreatorTest.java @@ -17,7 +17,7 @@ package io.helidon.pico.builder.config.tools.tests; import io.helidon.pico.builder.config.ConfigBean; -import io.helidon.pico.builder.config.processor.tools.ConfigBeanBuilderCreator; +import io.helidon.pico.builder.config.processor.ConfigBeanBuilderCreator; import io.helidon.builder.processor.spi.BuilderCreatorProvider; import org.junit.jupiter.api.Test; From 2d95c5b9bcd2d7839429f3996b37b51f9245fc92 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Thu, 1 Dec 2022 16:20:31 -0500 Subject: [PATCH 35/36] 1. allowNulls support added. 2. make config immutable on config bean. --- .../main/java/io/helidon/builder/Builder.java | 13 ++ .../builder/RequiredAttributeVisitor.java | 26 +++- .../builder/processor/tools/BodyContext.java | 112 +++++++++++------- .../tools/DefaultBuilderCreatorProvider.java | 54 ++++++--- .../tools/GenerateVisitorSupport.java | 23 +++- .../test/testsubjects/TestNotNullable.java | 35 ++++++ .../test/testsubjects/TestNullable.java | 35 ++++++ .../helidon/builder/test/AllowNullsTest.java | 57 +++++++++ etc/checkstyle-suppressions.xml | 2 + .../builder/config/spi/ConfigBeanBase.java | 21 ++-- .../config/spi/ConfigBeanBuilderBase.java | 20 +++- .../processor/ConfigBeanBuilderCreator.java | 7 +- .../config/testsubjects/CommonConfig.java | 2 + .../config/test/BasicConfigBeanTest.java | 33 ++++++ 14 files changed, 360 insertions(+), 80 deletions(-) create mode 100644 builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNotNullable.java create mode 100644 builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNullable.java create mode 100644 builder/tests/builder/src/test/java/io/helidon/builder/test/AllowNullsTest.java diff --git a/builder/builder/src/main/java/io/helidon/builder/Builder.java b/builder/builder/src/main/java/io/helidon/builder/Builder.java index 3664bba9c3a..72d145431df 100644 --- a/builder/builder/src/main/java/io/helidon/builder/Builder.java +++ b/builder/builder/src/main/java/io/helidon/builder/Builder.java @@ -62,6 +62,11 @@ */ String DEFAULT_SUFFIX = ""; + /** + * The default value for {@link #allowNulls()}. + */ + boolean DEFAULT_ALLOW_NULLS = false; + /** * The default list type used for the generated class implementation for any references to {@link java.util.List} is found * on the methods of the {@link Builder}-annotation interface. @@ -167,6 +172,14 @@ */ boolean requireBeanStyle() default false; + /** + * Should the bean and the builder allow for the possibility of nullable non-{@link java.util.Optional} values to be present. + * Default is {@code false}. + * + * @return true to allow for the possibility of nullable non-Optional values to be present + */ + boolean allowNulls() default DEFAULT_ALLOW_NULLS; + /** * The list implementation type to apply, defaulting to {@link #DEFAULT_LIST_TYPE}. * diff --git a/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java b/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java index cb8884f7a9a..aaee24ed362 100644 --- a/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java +++ b/builder/builder/src/main/java/io/helidon/builder/RequiredAttributeVisitor.java @@ -38,23 +38,42 @@ @Deprecated public class RequiredAttributeVisitor implements AttributeVisitor { private final List errors = new ArrayList<>(); + private final boolean allowNullsByDefault; /** * Default constructor. */ - // note: this needs to remain public since it will be new'ed from code-generated builder processing ... + // important note: this needs to remain public since it will be new'ed from code-generated builder processing ... public RequiredAttributeVisitor() { + this(Builder.DEFAULT_ALLOW_NULLS); + } + + /** + * Constructor. + * + * @param allowNullsByDefault true if nulls should be allowed + */ + // important note: this needs to remain public since it will be new'ed from code-generated builder processing ... + public RequiredAttributeVisitor(boolean allowNullsByDefault) { + this.allowNullsByDefault = allowNullsByDefault; } @Override + // important note: this needs to remain public since it will be new'ed from code-generated builder processing ... public void visit(String attrName, Supplier valueSupplier, Map meta, Object userDefinedCtx, Class type, Class... typeArgument) { - boolean required = Boolean.parseBoolean((String) meta.get("required")); - if (!required) { + String requiredStr = (String) meta.get("required"); + boolean requiredPresent = Objects.nonNull(requiredStr); + boolean required = Boolean.parseBoolean(requiredStr); + if (!required && requiredPresent) { + return; + } + + if (allowNullsByDefault && !requiredPresent) { return; } @@ -71,6 +90,7 @@ public void visit(String attrName, * * @throws java.lang.IllegalStateException when any attributes are in violation with the validation policy */ + // important note: this needs to remain public since it will be new'ed from code-generated builder processing ... public void validate() { if (!errors.isEmpty()) { throw new IllegalStateException(String.join(", ", errors)); diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java index 577f26760f8..19783dd34b1 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/BodyContext.java @@ -32,6 +32,7 @@ import io.helidon.pico.types.TypedElementName; import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.BUILDER_ANNO_TYPE_NAME; +import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_ALLOW_NULLS; import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_INCLUDE_META_ATTRIBUTES; import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_LIST_TYPE; import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_MAP_TYPE; @@ -49,7 +50,7 @@ public class BodyContext { private final boolean doingConcreteType; private final TypeName implTypeName; private final TypeInfo typeInfo; - private final AnnotationAndValue builderAnnotation; + private final AnnotationAndValue builderTriggerAnnotation; private final Map map = new LinkedHashMap<>(); private final List allTypeInfos = new ArrayList<>(); private final List allAttributeNames = new ArrayList<>(); @@ -59,7 +60,8 @@ public class BodyContext { private final boolean hasStreamSupportOnBuilder; private final boolean includeMetaAttributes; private final boolean requireLibraryDependencies; - private final boolean isBeanStyleRequired; + private final boolean beanStyleRequired; + private final boolean allowNulls; private final String listType; private final String mapType; private final String setType; @@ -75,32 +77,32 @@ public class BodyContext { * @param doingConcreteType true if the concrete type is being generated, otherwise the abstract class * @param implTypeName the impl type name * @param typeInfo the type info - * @param builderAnnotation the builder annotation + * @param builderTriggerAnnotation the builder annotation */ BodyContext(boolean doingConcreteType, TypeName implTypeName, TypeInfo typeInfo, - AnnotationAndValue builderAnnotation) { + AnnotationAndValue builderTriggerAnnotation) { this.doingConcreteType = doingConcreteType; this.implTypeName = implTypeName; this.typeInfo = typeInfo; - this.builderAnnotation = builderAnnotation; - this.hasStreamSupportOnImpl = hasStreamSupportOnImpl(doingConcreteType, builderAnnotation); - this.hasStreamSupportOnBuilder = hasStreamSupportOnBuilder(doingConcreteType, builderAnnotation); - this.includeMetaAttributes = toIncludeMetaAttributes(builderAnnotation, typeInfo); - this.requireLibraryDependencies = toRequireLibraryDependencies(builderAnnotation, typeInfo); - this.isBeanStyleRequired = toRequireBeanStyle(builderAnnotation, typeInfo); - this.listType = toListImplType(builderAnnotation, typeInfo); - this.mapType = toMapImplType(builderAnnotation, typeInfo); - this.setType = toSetImplType(builderAnnotation, typeInfo); + this.builderTriggerAnnotation = builderTriggerAnnotation; + this.hasStreamSupportOnImpl = hasStreamSupportOnImpl(doingConcreteType, builderTriggerAnnotation); + this.hasStreamSupportOnBuilder = hasStreamSupportOnBuilder(doingConcreteType, builderTriggerAnnotation); + this.includeMetaAttributes = toIncludeMetaAttributes(builderTriggerAnnotation, typeInfo); + this.requireLibraryDependencies = toRequireLibraryDependencies(builderTriggerAnnotation, typeInfo); + this.beanStyleRequired = toRequireBeanStyle(builderTriggerAnnotation, typeInfo); + this.allowNulls = toAllowNulls(builderTriggerAnnotation, typeInfo); + this.listType = toListImplType(builderTriggerAnnotation, typeInfo); + this.mapType = toMapImplType(builderTriggerAnnotation, typeInfo); + this.setType = toSetImplType(builderTriggerAnnotation, typeInfo); gatherAllAttributeNames(this, typeInfo); assert (allTypeInfos.size() == allAttributeNames.size()); this.hasParent = Objects.nonNull(parentTypeName.get()); this.ctorBuilderAcceptTypeName = (hasParent) ? typeInfo.typeName() - : ( - Objects.nonNull(parentAnnotationType.get()) && typeInfo.elementInfo().isEmpty() - ? typeInfo.superTypeInfo().get().typeName() : typeInfo.typeName()); + : (Objects.nonNull(parentAnnotationType.get()) && typeInfo.elementInfo().isEmpty() + ? typeInfo.superTypeInfo().orElseThrow().typeName() : typeInfo.typeName()); this.genericBuilderClassDecl = "Builder"; this.genericBuilderAliasDecl = ("B".equals(typeInfo.typeName().className())) ? "BU" : "B"; this.genericBuilderAcceptAliasDecl = ("T".equals(typeInfo.typeName().className())) ? "TY" : "T"; @@ -134,12 +136,13 @@ public TypeInfo typeInfo() { } /** - * Returns the builder annotation that triggers things. + * Returns the builder annotation that triggered things. * * @return the builder annotation + * @see io.helidon.builder.Builder */ - public AnnotationAndValue builderAnnotation() { - return builderAnnotation; + public AnnotationAndValue builderTriggerAnnotation() { + return builderTriggerAnnotation; } /** @@ -207,6 +210,7 @@ protected boolean hasStreamSupportOnBuilder() { /** * Returns true if meta attributes should be generated. + * See {@link io.helidon.builder.Builder#includeMetaAttributes()}. * * @return true if meta attributes should be generated */ @@ -216,6 +220,7 @@ protected boolean includeMetaAttributes() { /** * Returns true if Helidon library dependencies should be expected. + * See {@link io.helidon.builder.Builder#requireLibraryDependencies()}. * * @return true if Helidon library dependencies are expected */ @@ -225,15 +230,27 @@ protected boolean requireLibraryDependencies() { /** * Returns true if bean "getter" and "is" style is required. + * See {@link io.helidon.builder.Builder#requireBeanStyle()} . * * @return true if bean style is required */ - protected boolean isBeanStyleRequired() { - return isBeanStyleRequired; + protected boolean beanStyleRequired() { + return beanStyleRequired; + } + + /** + * Returns true if nulls are allowed. + * See {@link io.helidon.builder.Builder#allowNulls()}. + * + * @return true if allow nulls + */ + protected boolean allowNulls() { + return allowNulls; } /** * Returns the list type generated. + * See {@link io.helidon.builder.Builder#listImplType()}. * * @return the list type */ @@ -243,6 +260,7 @@ public String listType() { /** * Returns the map type generated. + * See {@link io.helidon.builder.Builder#mapImplType()}. * * @return the map type */ @@ -252,6 +270,7 @@ public String mapType() { /** * Returns the set type generated. + * See {@link io.helidon.builder.Builder#setImplType()}. * * @return the set type */ @@ -335,73 +354,86 @@ private static boolean hasStreamSupportOnBuilder(boolean ignoreDoingConcreteClas /** * In support of {@link io.helidon.builder.Builder#includeMetaAttributes()}. */ - private static boolean toIncludeMetaAttributes(AnnotationAndValue builderAnnotation, + private static boolean toIncludeMetaAttributes(AnnotationAndValue builderTriggerAnnotation, TypeInfo typeInfo) { - String val = searchForBuilderAnnotation("includeMetaAttributes", builderAnnotation, typeInfo); + String val = searchForBuilderAnnotation("includeMetaAttributes", builderTriggerAnnotation, typeInfo); return val == null ? DEFAULT_INCLUDE_META_ATTRIBUTES : Boolean.parseBoolean(val); } /** * In support of {@link io.helidon.builder.Builder#requireLibraryDependencies()}. */ - private static boolean toRequireLibraryDependencies(AnnotationAndValue builderAnnotation, + private static boolean toRequireLibraryDependencies(AnnotationAndValue builderTriggerAnnotation, TypeInfo typeInfo) { - String val = searchForBuilderAnnotation("requireLibraryDependencies", builderAnnotation, typeInfo); + String val = searchForBuilderAnnotation("requireLibraryDependencies", builderTriggerAnnotation, typeInfo); return val == null ? DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES : Boolean.parseBoolean(val); } /** * In support of {@link io.helidon.builder.Builder#requireBeanStyle()}. */ - private static boolean toRequireBeanStyle(AnnotationAndValue builderAnnotation, + private static boolean toRequireBeanStyle(AnnotationAndValue builderTriggerAnnotation, TypeInfo typeInfo) { - String val = searchForBuilderAnnotation("requireBeanStyle", builderAnnotation, typeInfo); + String val = searchForBuilderAnnotation("requireBeanStyle", builderTriggerAnnotation, typeInfo); return Boolean.parseBoolean(val); } + /** + * In support of {@link io.helidon.builder.Builder#allowNulls()} ()}. + */ + private static boolean toAllowNulls(AnnotationAndValue builderTriggerAnnotation, + TypeInfo typeInfo) { + String val = searchForBuilderAnnotation("allowNulls", builderTriggerAnnotation, typeInfo); + return val == null ? DEFAULT_ALLOW_NULLS : Boolean.parseBoolean(val); + } + /** * In support of {@link io.helidon.builder.Builder#listImplType()}. */ - private static String toListImplType(AnnotationAndValue builderAnnotation, + private static String toListImplType(AnnotationAndValue builderTriggerAnnotation, TypeInfo typeInfo) { - String type = searchForBuilderAnnotation("listImplType", builderAnnotation, typeInfo); + String type = searchForBuilderAnnotation("listImplType", builderTriggerAnnotation, typeInfo); return (!BuilderTypeTools.hasNonBlankValue(type)) ? DEFAULT_LIST_TYPE : type; } /** * In support of {@link io.helidon.builder.Builder#mapImplType()} ()}. */ - private static String toMapImplType(AnnotationAndValue builderAnnotation, + private static String toMapImplType(AnnotationAndValue builderTriggerAnnotation, TypeInfo typeInfo) { - String type = searchForBuilderAnnotation("mapImplType", builderAnnotation, typeInfo); + String type = searchForBuilderAnnotation("mapImplType", builderTriggerAnnotation, typeInfo); return (!BuilderTypeTools.hasNonBlankValue(type)) ? DEFAULT_MAP_TYPE : type; } /** * In support of {@link io.helidon.builder.Builder#setImplType()}. */ - private static String toSetImplType(AnnotationAndValue builderAnnotation, + private static String toSetImplType(AnnotationAndValue builderTriggerAnnotation, TypeInfo typeInfo) { - String type = searchForBuilderAnnotation("setImplType", builderAnnotation, typeInfo); + String type = searchForBuilderAnnotation("setImplType", builderTriggerAnnotation, typeInfo); return (!BuilderTypeTools.hasNonBlankValue(type)) ? DEFAULT_SET_TYPE : type; } private static String searchForBuilderAnnotation(String key, - AnnotationAndValue builderAnnotation, + AnnotationAndValue builderTriggerAnnotation, TypeInfo typeInfo) { - String val = builderAnnotation.value(key).orElse(null); + String val = builderTriggerAnnotation.value(key).orElse(null); if (val != null) { return val; } - if (!builderAnnotation.typeName().equals(BUILDER_ANNO_TYPE_NAME)) { - builderAnnotation = DefaultAnnotationAndValue + if (!builderTriggerAnnotation.typeName().equals(BUILDER_ANNO_TYPE_NAME)) { + AnnotationAndValue builderAnnotation = DefaultAnnotationAndValue .findFirst(BUILDER_ANNO_TYPE_NAME.name(), typeInfo.annotations()).orElse(null); if (Objects.nonNull(builderAnnotation)) { val = builderAnnotation.value(key).orElse(null); } } + if (val == null && typeInfo.superTypeInfo().isPresent()) { + val = searchForBuilderAnnotation(key, builderTriggerAnnotation, typeInfo.superTypeInfo().get()); + } + return val; } @@ -410,11 +442,11 @@ private static void gatherAllAttributeNames(BodyContext ctx, TypeInfo superTypeInfo = typeInfo.superTypeInfo().orElse(null); if (Objects.nonNull(superTypeInfo)) { Optional superBuilderAnnotation = DefaultAnnotationAndValue - .findFirst(ctx.builderAnnotation.typeName().name(), superTypeInfo.annotations()); + .findFirst(ctx.builderTriggerAnnotation.typeName().name(), superTypeInfo.annotations()); if (superBuilderAnnotation.isEmpty()) { gatherAllAttributeNames(ctx, superTypeInfo); } else { - populateMap(ctx.map, superTypeInfo, ctx.isBeanStyleRequired); + populateMap(ctx.map, superTypeInfo, ctx.beanStyleRequired); } if (Objects.isNull(ctx.parentTypeName.get()) @@ -427,7 +459,7 @@ private static void gatherAllAttributeNames(BodyContext ctx, } for (TypedElementName method : typeInfo.elementInfo()) { - String beanAttributeName = toBeanAttributeName(method, ctx.isBeanStyleRequired); + String beanAttributeName = toBeanAttributeName(method, ctx.beanStyleRequired); TypedElementName existing = ctx.map.get(beanAttributeName); if (Objects.nonNull(existing) && BeanUtils.isBooleanType(method.typeName().name()) diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java index 4a1daff044d..e6cc3f58c38 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/DefaultBuilderCreatorProvider.java @@ -58,6 +58,7 @@ public class DefaultBuilderCreatorProvider implements BuilderCreatorProvider { static final boolean DEFAULT_INCLUDE_META_ATTRIBUTES = true; static final boolean DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES = true; + static final boolean DEFAULT_ALLOW_NULLS = false; static final String DEFAULT_IMPL_PREFIX = Builder.DEFAULT_IMPL_PREFIX; static final String DEFAULT_ABSTRACT_IMPL_PREFIX = Builder.DEFAULT_ABSTRACT_IMPL_PREFIX; static final String DEFAULT_SUFFIX = Builder.DEFAULT_SUFFIX; @@ -227,7 +228,8 @@ protected void appendFooter(StringBuilder builder, protected void appendRequiredValidator(StringBuilder builder, BodyContext ctx) { if (ctx.includeMetaAttributes()) { - builder.append("\t\t\tRequiredAttributeVisitor visitor = new RequiredAttributeVisitor();\n" + builder.append("\t\t\tRequiredAttributeVisitor visitor = new RequiredAttributeVisitor(") + .append(ctx.allowNulls()).append(");\n" + "\t\t\tvisitAttributes(visitor, null);\n" + "\t\t\tvisitor.validate();\n"); } @@ -343,10 +345,10 @@ protected void appendHeader(StringBuilder builder, } if (ctx.doingConcreteType()) { - builder.append(toAbstractImplTypeName(ctx.typeInfo().typeName(), ctx.builderAnnotation()).get()); + builder.append(toAbstractImplTypeName(ctx.typeInfo().typeName(), ctx.builderTriggerAnnotation()).get()); } else { if (ctx.hasParent()) { - builder.append(toAbstractImplTypeName(ctx.parentTypeName().get(), ctx.builderAnnotation()).get()); + builder.append(toAbstractImplTypeName(ctx.parentTypeName().get(), ctx.builderTriggerAnnotation()).get()); } else { Optional baseExtendsTypeName = baseExtendsTypeName(ctx); if (baseExtendsTypeName.isPresent()) { @@ -601,7 +603,7 @@ protected void appendExtraFields(StringBuilder builder, BodyContext ctx) { if (!ctx.doingConcreteType() && ctx.includeMetaAttributes()) { GenerateJavadoc.internalMetaPropsField(builder); - builder.append("\tprotected static final Map> ") + builder.append("\tprivate static final Map> ") .append(TAG_META_PROPS).append(" = Collections.unmodifiableMap(__calcMeta());\n"); } } @@ -762,21 +764,25 @@ protected void appendSetter(StringBuilder mainBuilder, builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".addAll(Objects.requireNonNull(val));\n"); + .append(".addAll(").append(maybeRequireNonNull(ctx, "val")).append(");\n"); } else if (isMap) { builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".putAll(Objects.requireNonNull(val));\n"); + .append(".putAll(").append(maybeRequireNonNull(ctx, "val")).append(");\n"); } else if (isSet) { builder.append(".clear();\n"); builder.append("\t\t\tthis.") .append(beanAttributeName) - .append(".addAll(Objects.requireNonNull(val));\n"); + .append(".addAll(").append(maybeRequireNonNull(ctx, "val")).append(");\n"); } else if (typeName.array()) { - builder.append(" = val.clone();\n"); + if (ctx.allowNulls()) { + builder.append(" = (val == null) ? null : val.clone();\n"); + } else { + builder.append(" = val.clone();\n"); + } } else { - builder.append(" = Objects.requireNonNull(val);\n"); + builder.append(" = ").append(maybeRequireNonNull(ctx, "val")).append(";\n"); } builder.append("\t\t\treturn identity();\n"); builder.append("\t\t}\n\n"); @@ -1099,7 +1105,9 @@ private void appendBuilder(StringBuilder builder, builder.append("\t\tpublic ") .append(ctx.genericBuilderAliasDecl()) .append(" accept(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); - builder.append("\t\t\tObjects.requireNonNull(val);\n"); + if (!ctx.allowNulls()) { + builder.append("\t\t\tObjects.requireNonNull(val);\n"); + } if (ctx.hasParent()) { builder.append("\t\t\tsuper.accept(val);\n"); } @@ -1108,7 +1116,9 @@ private void appendBuilder(StringBuilder builder, builder.append("\t\t}\n\n"); builder.append("\t\tprivate void __acceptThis(").append(ctx.genericBuilderAcceptAliasDecl()).append(" val) {\n"); - + if (!ctx.allowNulls()) { + builder.append("\t\t\tObjects.requireNonNull(val);\n"); + } i = 0; for (String beanAttributeName : ctx.allAttributeNames()) { TypedElementName method = ctx.allTypeInfos().get(i++); @@ -1123,7 +1133,15 @@ private void appendBuilder(StringBuilder builder, } else if (isMap) { builder.append("(java.util.Map) "); } - builder.append("val.").append(getterName).append("());\n"); + boolean isPrimitive = method.typeName().primitive(); + if (!isPrimitive && ctx.allowNulls()) { + builder.append("((val == null) ? null : "); + } + builder.append("val.").append(getterName).append("()"); + if (!isPrimitive && ctx.allowNulls()) { + builder.append(")"); + } + builder.append(");\n"); } builder.append("\t\t}\n\n"); } @@ -1234,7 +1252,7 @@ private void appendBuilderHeader(StringBuilder builder, if (ctx.doingConcreteType()) { builder.append(" extends "); - builder.append(toAbstractImplTypeName(ctx.typeInfo().typeName(), ctx.builderAnnotation()).get()); + builder.append(toAbstractImplTypeName(ctx.typeInfo().typeName(), ctx.builderTriggerAnnotation()).get()); builder.append(".").append(ctx.genericBuilderClassDecl()); builder.append("<").append(ctx.genericBuilderClassDecl()).append(", ").append(ctx.ctorBuilderAcceptTypeName()) .append("> {\n"); @@ -1246,7 +1264,7 @@ private void appendBuilderHeader(StringBuilder builder, builder.append(ctx.ctorBuilderAcceptTypeName()).append("> "); if (ctx.hasParent()) { builder.append("extends ") - .append(toAbstractImplTypeName(ctx.parentTypeName().get(), ctx.builderAnnotation()).get()) + .append(toAbstractImplTypeName(ctx.parentTypeName().get(), ctx.builderTriggerAnnotation()).get()) .append(".").append(ctx.genericBuilderClassDecl()); builder.append("<").append(ctx.genericBuilderAliasDecl()) .append(", ").append(ctx.genericBuilderAcceptAliasDecl()); @@ -1511,11 +1529,11 @@ private void appendOverridesOfDefaultValues(StringBuilder builder, BodyContext ctx) { boolean first = true; for (TypedElementName method : ctx.typeInfo().elementInfo()) { - String beanAttributeName = toBeanAttributeName(method, ctx.isBeanStyleRequired()); + String beanAttributeName = toBeanAttributeName(method, ctx.beanStyleRequired()); if (!ctx.allAttributeNames().contains(beanAttributeName)) { // candidate for override... String thisDefault = toConfiguredOptionValue(method, true, true).orElse(null); - String superDefault = superValue(ctx.typeInfo().superTypeInfo(), beanAttributeName, ctx.isBeanStyleRequired()); + String superDefault = superValue(ctx.typeInfo().superTypeInfo(), beanAttributeName, ctx.beanStyleRequired()); if (BuilderTypeTools.hasNonBlankValue(thisDefault) && !Objects.equals(thisDefault, superDefault)) { appendDefaultOverride(builder, beanAttributeName, method, thisDefault); } @@ -1639,4 +1657,8 @@ private String quotedValueOf(String val) { return "\"" + val + "\""; } + private String maybeRequireNonNull(BodyContext ctx, String tag) { + return ctx.allowNulls() ? tag : "Objects.requireNonNull(" + tag + ")"; + } + } diff --git a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java index 72b7d1b32fc..9756d164652 100644 --- a/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java +++ b/builder/processor-tools/src/main/java/io/helidon/builder/processor/tools/GenerateVisitorSupport.java @@ -16,6 +16,9 @@ package io.helidon.builder.processor.tools; +/** + * See {@link io.helidon.builder.RequiredAttributeVisitor} for the prototypical output for this generated class. + */ final class GenerateVisitorSupport { private GenerateVisitorSupport() { } @@ -60,11 +63,21 @@ static void appendExtraInnerClasses(StringBuilder builder, + "\t */\n"); builder.append("\tprotected static class RequiredAttributeVisitor implements AttributeVisitor {\n" + "\t\tprivate final List errors = new java.util.ArrayList();\n" + + "\t\tprivate final boolean allowNullsByDefault;\n" + "\n" + "\t\t/**\n" + "\t\t * Default Constructor.\n" + "\t\t */\n" + "\t\tprotected RequiredAttributeVisitor() {\n" + + "\t\t\tthis(" + ctx.allowNulls() + ");\n" + + "\t\t}\n\n"); + builder.append("\t\t/**\n" + + "\t\t * Constructor.\n" + + "\t\t *\n" + + "\t\t * @param allowNullsByDefault true if nulls should be allowed\n" + + "\t\t */\n" + + "\t\tpublic RequiredAttributeVisitor(boolean allowNullsByDefault) {\n" + + "\t\t\tthis.allowNullsByDefault = allowNullsByDefault;\n" + "\t\t}\n\n"); builder.append("\t\t@Override\n" + "\t\tpublic void visit(String attrName,\n" @@ -73,8 +86,14 @@ static void appendExtraInnerClasses(StringBuilder builder, + "\t\t\t\t\t\t Object userDefinedCtx,\n" + "\t\t\t\t\t\t Class type,\n" + "\t\t\t\t\t\t Class... typeArgument) {\n" - + "\t\t\tboolean required = Boolean.valueOf((String) meta.get(\"required\"));\n" - + "\t\t\tif (!required) {\n" + + "\t\t\tString requiredStr = (String) meta.get(\"required\");\n" + + "\t\t\tboolean requiredPresent = Objects.nonNull(requiredStr);\n" + + "\t\t\tboolean required = Boolean.parseBoolean(requiredStr);\n" + + "\t\t\tif (!required && requiredPresent) {\n" + + "\t\t\t\treturn;\n" + + "\t\t\t}\n" + + "\n" + + "\t\t\tif (allowNullsByDefault && !requiredPresent) {\n" + "\t\t\t\treturn;\n" + "\t\t\t}\n" + "\t\t\t\n" diff --git a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNotNullable.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNotNullable.java new file mode 100644 index 00000000000..070af19baaa --- /dev/null +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNotNullable.java @@ -0,0 +1,35 @@ +/* + * 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.builder.test.testsubjects; + +import io.helidon.builder.Builder; + +/** + * The default for builder is to not allow for nullable attributes. + */ +@Builder +@FunctionalInterface +public interface TestNotNullable { + + /** + * Cannot be null. + * + * @return a nonNull value + */ + String val(); + +} diff --git a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNullable.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNullable.java new file mode 100644 index 00000000000..9895879dd1c --- /dev/null +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/TestNullable.java @@ -0,0 +1,35 @@ +/* + * 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.builder.test.testsubjects; + +import io.helidon.builder.Builder; + +/** + * Overrides builder default to allow for null attributes. + */ +@Builder(allowNulls = true) +@FunctionalInterface +public interface TestNullable { + + /** + * A possibly null value. + * + * @return a possible null value + */ + String val(); + +} diff --git a/builder/tests/builder/src/test/java/io/helidon/builder/test/AllowNullsTest.java b/builder/tests/builder/src/test/java/io/helidon/builder/test/AllowNullsTest.java new file mode 100644 index 00000000000..cce52f735e4 --- /dev/null +++ b/builder/tests/builder/src/test/java/io/helidon/builder/test/AllowNullsTest.java @@ -0,0 +1,57 @@ +/* + * 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.builder.test; + +import io.helidon.builder.test.testsubjects.DefaultTestNotNullable; +import io.helidon.builder.test.testsubjects.DefaultTestNullable; +import io.helidon.builder.test.testsubjects.TestNotNullable; +import io.helidon.builder.test.testsubjects.TestNullable; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +class AllowNullsTest { + + @Test + void testIt() { + TestNullable nullable = DefaultTestNullable.builder().build(); + assertThat(nullable.val(), nullValue()); + + nullable = DefaultTestNullable.builder().val(null).build(); + assertThat(nullable.val(), nullValue()); + + nullable = DefaultTestNullable.toBuilder(nullable).build(); + assertThat(nullable.val(), nullValue()); + + TestNotNullable fake = () -> null; + try { + DefaultTestNotNullable.toBuilder(fake); + fail(); + } catch (NullPointerException e) { + // expected + } + + DefaultTestNotNullable.Builder notNullableBuilder = DefaultTestNotNullable.builder(); + assertThrows(NullPointerException.class, () -> notNullableBuilder.val(null)); + assertThrows(IllegalStateException.class, notNullableBuilder::build); + } + +} diff --git a/etc/checkstyle-suppressions.xml b/etc/checkstyle-suppressions.xml index 5480f22d5bf..b7b05f82bc9 100644 --- a/etc/checkstyle-suppressions.xml +++ b/etc/checkstyle-suppressions.xml @@ -84,6 +84,8 @@ checks="MethodName"/> + diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBase.java index 309e869cc60..bfe60a7b04f 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBase.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBase.java @@ -16,7 +16,6 @@ package io.helidon.pico.builder.config.spi; -import java.util.Objects; import java.util.Optional; import io.helidon.common.config.Config; @@ -27,13 +26,18 @@ * @deprecated this is for internal use only */ public abstract class ConfigBeanBase implements ConfigBeanCommon { - private Config cfg; + private final Config cfg; private String instanceId; /** * Protected constructor for initializing the generated config bean instance variables. + * @param b the builder + * @param instanceId the instance id */ - protected ConfigBeanBase() { + protected ConfigBeanBase(ConfigBeanBuilder b, + String instanceId) { + this.cfg = b.__config().orElse(null); + this.instanceId = instanceId; } @Override @@ -41,15 +45,6 @@ public Optional __config() { return Optional.ofNullable(cfg); } - /** - * Sets the config instance. - * - * @param cfg the config instance - */ - public void __config(Config cfg) { - this.cfg = Objects.requireNonNull(cfg); - } - /** * Returns the instance id assigned to this bean. * @@ -65,7 +60,7 @@ public String __instanceId() { * @param val the new instance id for this bean */ public void __instanceId(String val) { - instanceId = val; + this.instanceId = val; } } diff --git a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java index 527ceea0310..e592c256526 100644 --- a/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java +++ b/pico/builder-config/builder-config/src/main/java/io/helidon/pico/builder/config/spi/ConfigBeanBuilderBase.java @@ -16,6 +16,9 @@ package io.helidon.pico.builder.config.spi; +import java.util.Objects; +import java.util.Optional; + import io.helidon.common.config.Config; /** @@ -23,7 +26,8 @@ * * @deprecated this is for internal use only */ -public abstract class ConfigBeanBuilderBase extends ConfigBeanBase implements ConfigBeanBuilder { +public abstract class ConfigBeanBuilderBase implements ConfigBeanBuilder { + private Config cfg; /** * Default constructor. Reserved for internal use. @@ -44,6 +48,20 @@ public void acceptConfig(Config cfg, } } + @Override + public Optional __config() { + return Optional.ofNullable(cfg); + } + + /** + * Sets the config instance. + * + * @param cfg the config instance + */ + public void __config(Config cfg) { + this.cfg = Objects.requireNonNull(cfg); + } + /** * Creates a resolution context. * diff --git a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/ConfigBeanBuilderCreator.java b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/ConfigBeanBuilderCreator.java index 496e1c4951d..c1e3b2969df 100644 --- a/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/ConfigBeanBuilderCreator.java +++ b/pico/builder-config/processor/src/main/java/io/helidon/pico/builder/config/processor/ConfigBeanBuilderCreator.java @@ -167,10 +167,7 @@ protected void appendExtraCtorCode(StringBuilder builder, BodyContext ctx, String builderTag) { if (!ctx.hasParent()) { - builder.append("\t\t__instanceId(String.valueOf(__INSTANCE_ID.getAndIncrement()));\n"); - builder.append("\t\tif (b.__config().isPresent()) {\n" - + "\t\t\t__config(").append(builderTag).append(".__config().get());\n" - + "\t\t}\n"); + builder.append("\t\tsuper(b, String.valueOf(__INSTANCE_ID.getAndIncrement()));\n"); } super.appendExtraCtorCode(builder, ctx, builderTag); @@ -229,7 +226,7 @@ protected void appendExtraBuilderMethods(StringBuilder builder, int i = 0; for (String attrName : ctx.allAttributeNames()) { TypedElementName method = ctx.allTypeInfos().get(i); - String configKey = toConfigKey(attrName, method, ctx.builderAnnotation()); + String configKey = toConfigKey(attrName, method, ctx.builderTriggerAnnotation()); // resolver.of(config, "port", int.class).ifPresent(this::port); String ofClause = "of"; diff --git a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java index fcd20417939..364f7c228f9 100644 --- a/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java +++ b/pico/builder-config/tests/configbean/src/main/java/io/helidon/pico/builder/config/testsubjects/CommonConfig.java @@ -18,6 +18,7 @@ import java.util.List; +import io.helidon.builder.Builder; import io.helidon.config.metadata.ConfiguredOption; import io.helidon.pico.builder.config.ConfigBean; @@ -25,6 +26,7 @@ * For testing purpose. */ @ConfigBean +@Builder(allowNulls = true) public interface CommonConfig { /** diff --git a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java index f66904e5e6a..cfdbe87cadd 100644 --- a/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java +++ b/pico/builder-config/tests/configbean/src/test/java/io/helidon/pico/builder/config/test/BasicConfigBeanTest.java @@ -16,10 +16,13 @@ package io.helidon.pico.builder.config.test; +import java.util.List; import java.util.Map; import io.helidon.config.Config; import io.helidon.config.ConfigSources; +import io.helidon.pico.builder.config.testsubjects.ClientConfig; +import io.helidon.pico.builder.config.testsubjects.DefaultClientConfig; import io.helidon.pico.builder.config.testsubjects.DefaultServerConfig; import io.helidon.pico.builder.config.testsubjects.ServerConfig; @@ -68,4 +71,34 @@ void emptyConfig() { assertThat(serverConfig.port(), equalTo(0)); } + /** + * Callers can conceptually use config beans as just plain old vanilla builders, void of any config usage. + */ + @Test + void noConfig() { + ServerConfig serverConfig = DefaultServerConfig.builder().build(); + assertThat(serverConfig.description(), optionalEmpty()); + assertThat(serverConfig.name(), equalTo("default")); + assertThat(serverConfig.port(), equalTo(0)); + assertThat(serverConfig.cipherSuites(), equalTo(List.of())); + + serverConfig = DefaultServerConfig.toBuilder(serverConfig).port(123).build(); + assertThat(serverConfig.description(), optionalEmpty()); + assertThat(serverConfig.name(), equalTo("default")); + assertThat(serverConfig.port(), equalTo(123)); + assertThat(serverConfig.cipherSuites(), equalTo(List.of())); + + ClientConfig clientConfig = DefaultClientConfig.builder().build(); + assertThat(clientConfig.name(), equalTo("default")); + assertThat(clientConfig.port(), equalTo(0)); + assertThat(clientConfig.headers(), equalTo(Map.of())); + assertThat(clientConfig.cipherSuites(), equalTo(List.of())); + + clientConfig = DefaultClientConfig.toBuilder(clientConfig).port(123).build(); + assertThat(clientConfig.name(), equalTo("default")); + assertThat(clientConfig.port(), equalTo(123)); + assertThat(clientConfig.headers(), equalTo(Map.of())); + assertThat(clientConfig.cipherSuites(), equalTo(List.of())); + } + } From 85fdb091c016ab001cc1ed7a1a337bd68f63c186 Mon Sep 17 00:00:00 2001 From: Jeff Trent Date: Thu, 1 Dec 2022 17:09:31 -0500 Subject: [PATCH 36/36] fix failing test --- .../src/main/java/io/helidon/pico/ContextualServiceQuery.java | 4 +++- pico/pico/src/main/java/io/helidon/pico/PicoServices.java | 1 + .../src/main/java/io/helidon/pico/ServiceInfoCriteria.java | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java b/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java index 9d5a866c5df..63b23da1150 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java +++ b/pico/pico/src/main/java/io/helidon/pico/ContextualServiceQuery.java @@ -16,6 +16,8 @@ package io.helidon.pico; +import java.util.Optional; + import io.helidon.builder.Builder; /** @@ -39,7 +41,7 @@ public interface ContextualServiceQuery { * * @return the injection point context info */ - InjectionPointInfo ipInfo(); + Optional ipInfo(); /** * Set to true if there is an expectation that there is at least one match result from the search. diff --git a/pico/pico/src/main/java/io/helidon/pico/PicoServices.java b/pico/pico/src/main/java/io/helidon/pico/PicoServices.java index 1e37b059d30..f2367951ad8 100644 --- a/pico/pico/src/main/java/io/helidon/pico/PicoServices.java +++ b/pico/pico/src/main/java/io/helidon/pico/PicoServices.java @@ -24,6 +24,7 @@ * An implementation of this interface must minimally supply a "services registry" - see {@link #services()}. */ public interface PicoServices { + /** * Empty criteria will match anything and everything. */ diff --git a/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java b/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java index b43a1c64846..3053d95fb4c 100644 --- a/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java +++ b/pico/pico/src/main/java/io/helidon/pico/ServiceInfoCriteria.java @@ -27,6 +27,7 @@ */ @Builder public interface ServiceInfoCriteria { + /** * The managed service implementation {@link Class}. * @@ -97,4 +98,5 @@ public interface ServiceInfoCriteria { * @return the module name */ Optional moduleName(); + }