From fb023c899d1bc8d1c1e0e4efe2af3e8b0252339b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kraus?= Date: Fri, 23 Feb 2024 17:10:14 +0100 Subject: [PATCH 1/8] PostgreSQL JDBC driver updated to 42.4.4. (#8414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Kraus --- dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 5ef8c59cf26..2ba880b0445 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -145,7 +145,7 @@ 0.1.8 0.25.0 1.0.5 - 42.4.3 + 42.4.4 0.9.0 2.0.9 2.1.16 From 3de3a8040345cd18b232ed540b5b2d5deb6d2f4d Mon Sep 17 00:00:00 2001 From: Andrei Arlou Date: Thu, 29 Feb 2024 19:13:26 +0200 Subject: [PATCH 2/8] [3.x] Replace deprecated Multi.from(Stream) on Multi.create(Stream) (#8438) --- .../io/helidon/messaging/connectors/kafka/KafkaSeTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaSeTest.java b/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaSeTest.java index 34bbc4ce99f..2106672e19e 100644 --- a/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaSeTest.java +++ b/tests/integration/kafka/src/test/java/io/helidon/messaging/connectors/kafka/KafkaSeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -425,7 +425,7 @@ void kafkaHeaderTest() throws InterruptedException { Messaging messaging = Messaging.builder() .connector(kafkaConnector) .publisher(toKafka, - Multi.from(IntStream.rangeClosed(1, 3).boxed()) + Multi.create(IntStream.rangeClosed(1, 3).boxed()) .map(KafkaMessage::of) .peek(msg -> msg.getHeaders() .add("secret header", From 4a017fbfef75ec738db87f11fcb3d0cac0951707 Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Thu, 29 Feb 2024 09:35:55 -0800 Subject: [PATCH 3/8] 3.x example removal (#8437) Delete examples from Helidon 3 Update the examples top level README to direct users to helidon-examples Update the examples profile to include a module called helidon-examples (instead of examples) Add a build-examples script that clones the helidon-examples repository into the helidon-examples directory (if it doesn't already exist) and builds the examples. --- .github/workflows/validate.yaml | 3 +- .gitignore | 3 + etc/scripts/build-examples.sh | 44 ++ etc/scripts/checkstyle.sh | 4 +- examples/README.md | 39 +- examples/config/README.md | 5 - examples/config/basics/README.md | 16 - examples/config/basics/pom.xml | 65 --- .../helidon/config/examples/basics/Main.java | 56 --- .../config/examples/basics/package-info.java | 20 - .../src/main/resources/application.conf | 69 --- .../src/main/resources/logging.properties | 26 - examples/config/changes/README.md | 29 -- examples/config/changes/conf/config.yaml | 21 - examples/config/changes/conf/dev.yaml | 25 - examples/config/changes/conf/secrets/password | 1 - examples/config/changes/conf/secrets/username | 1 - examples/config/changes/pom.xml | 69 --- .../examples/changes/AsSupplierExample.java | 108 ---- .../helidon/config/examples/changes/Main.java | 56 --- .../examples/changes/OnChangeExample.java | 60 --- .../config/examples/changes/package-info.java | 20 - .../changes/src/main/resources/default.yaml | 24 - .../src/main/resources/logging.properties | 26 - examples/config/git/README.md | 28 -- examples/config/git/pom.xml | 82 --- .../io/helidon/config/examples/git/Main.java | 81 --- .../config/examples/git/package-info.java | 20 - .../git/src/main/resources/logging.properties | 26 - examples/config/mapping/README.md | 23 - examples/config/mapping/pom.xml | 69 --- .../examples/mapping/BuilderExample.java | 184 ------- .../mapping/DeserializationExample.java | 146 ------ .../mapping/FactoryMethodExample.java | 129 ----- .../helidon/config/examples/mapping/Main.java | 38 -- .../config/examples/mapping/package-info.java | 20 - .../src/main/resources/application.conf | 21 - .../src/main/resources/logging.properties | 26 - examples/config/metadata/README.md | 24 - examples/config/metadata/pom.xml | 66 --- .../examples/metadata/ConfigMetadataMain.java | 462 ----------------- .../examples/metadata/ConfiguredType.java | 361 -------------- .../examples/metadata/package-info.java | 20 - examples/config/overrides/README.md | 27 - .../overrides/conf/overrides.properties | 29 -- .../overrides/conf/priority-config.yaml | 29 -- examples/config/overrides/pom.xml | 61 --- .../config/examples/overrides/Main.java | 109 ---- .../examples/overrides/package-info.java | 20 - .../src/main/resources/application.yaml | 35 -- .../src/main/resources/logging.properties | 26 - examples/config/pom.xml | 44 -- examples/config/profiles/README.md | 31 -- .../config/profiles/config-profile-prod.yaml | 22 - .../config/profiles/config/config-prod.yaml | 17 - examples/config/profiles/pom.xml | 65 --- .../examples/config/profiles/Main.java | 38 -- .../config/profiles/package-info.java | 20 - .../src/main/resources/application-local.yaml | 17 - .../src/main/resources/application-stage.yaml | 17 - .../src/main/resources/application.yaml | 17 - .../main/resources/config-profile-dev.yaml | 20 - .../main/resources/config-profile-stage.yaml | 20 - examples/config/sources/README.md | 23 - examples/config/sources/conf/config.yaml | 25 - examples/config/sources/conf/dev.yaml | 30 -- examples/config/sources/conf/meta-config.yaml | 30 -- examples/config/sources/conf/secrets/password | 1 - examples/config/sources/conf/secrets/username | 1 - examples/config/sources/pom.xml | 65 --- .../sources/DirectorySourceExample.java | 56 --- .../examples/sources/LoadSourcesExample.java | 78 --- .../helidon/config/examples/sources/Main.java | 38 -- .../examples/sources/WithSourcesExample.java | 77 --- .../config/examples/sources/package-info.java | 20 - .../sources/src/main/resources/default.yaml | 32 -- .../src/main/resources/logging.properties | 26 - .../src/main/resources/meta-config.yaml | 21 - .../src/main/resources/overrides.properties | 17 - examples/cors/README.md | 169 ------- examples/cors/pom.xml | 96 ---- .../helidon/examples/cors/GreetService.java | 125 ----- .../examples/cors/GreetingMessage.java | 87 ---- .../java/io/helidon/examples/cors/Main.java | 138 ------ .../helidon/examples/cors/package-info.java | 24 - .../src/main/resources/META-INF/openapi.yml | 79 --- .../cors/src/main/resources/application.yaml | 34 -- .../src/main/resources/logging.properties | 30 -- .../io/helidon/examples/cors/MainTest.java | 245 --------- examples/dbclient/README.md | 8 - examples/dbclient/common/pom.xml | 45 -- .../common/AbstractPokemonService.java | 240 --------- .../examples/dbclient/common/Pokemon.java | 61 --- .../dbclient/common/PokemonMapper.java | 59 --- .../common/PokemonMapperProvider.java | 40 -- .../dbclient/common/package-info.java | 19 - .../io.helidon.dbclient.spi.DbMapperProvider | 17 - examples/dbclient/jdbc/README.md | 69 --- examples/dbclient/jdbc/pom.xml | 132 ----- .../dbclient/jdbc/JdbcExampleMain.java | 111 ----- .../dbclient/jdbc/PokemonService.java | 66 --- .../examples/dbclient/jdbc/package-info.java | 20 - .../jdbc/src/main/resources/application.yaml | 108 ---- .../src/main/resources/logging.properties | 36 -- examples/dbclient/mongodb/README.md | 50 -- examples/dbclient/mongodb/pom.xml | 115 ----- .../dbclient/mongo/MongoDbExampleMain.java | 122 ----- .../dbclient/mongo/PokemonService.java | 59 --- .../examples/dbclient/mongo/package-info.java | 20 - .../src/main/resources/application.yaml | 75 --- .../src/main/resources/logging.properties | 36 -- examples/dbclient/pokemons/README.md | 128 ----- examples/dbclient/pokemons/pom.xml | 139 ------ .../dbclient/pokemons/InitializeDb.java | 155 ------ .../examples/dbclient/pokemons/Pokemon.java | 71 --- .../dbclient/pokemons/PokemonMain.java | 130 ----- .../dbclient/pokemons/PokemonMapper.java | 57 --- .../pokemons/PokemonMapperProvider.java | 40 -- .../dbclient/pokemons/PokemonService.java | 270 ---------- .../dbclient/pokemons/package-info.java | 20 - .../io.helidon.dbclient.spi.DbMapperProvider | 17 - .../pokemons/src/main/resources/Pokemons.json | 8 - .../pokemons/src/main/resources/Types.json | 20 - .../src/main/resources/application.yaml | 92 ---- .../src/main/resources/logging.properties | 36 -- .../pokemons/src/main/resources/mongo.yaml | 114 ----- examples/dbclient/pom.xml | 45 -- examples/employee-app/.dockerignore | 1 - examples/employee-app/Dockerfile | 45 -- examples/employee-app/README.md | 293 ----------- examples/employee-app/app.yaml | 63 --- examples/employee-app/pom.xml | 116 ----- .../io/helidon/service/employee/Employee.java | 153 ------ .../service/employee/EmployeeRepository.java | 114 ----- .../employee/EmployeeRepositoryImpl.java | 128 ----- .../employee/EmployeeRepositoryImplDB.java | 167 ------- .../service/employee/EmployeeService.java | 240 --------- .../io/helidon/service/employee/Main.java | 106 ---- .../service/employee/package-info.java | 24 - .../src/main/resources/application.yaml | 29 -- .../src/main/resources/employees.json | 402 --------------- .../src/main/resources/logging.properties | 34 -- .../resources/public/EmployeeController.js | 218 -------- .../src/main/resources/public/index.html | 399 --------------- .../src/main/resources/public/nopic.png | Bin 3584 -> 0 bytes .../io/helidon/service/employee/MainTest.java | 86 ---- examples/graphql/basics/README.md | 33 -- examples/graphql/basics/pom.xml | 69 --- .../helidon/examples/graphql/basics/Main.java | 87 ---- .../examples/graphql/basics/package-info.java | 19 - examples/graphql/pom.xml | 35 -- examples/grpc/.dockerignore | 1 - examples/grpc/README.md | 1 - examples/grpc/basics/README.md | 24 - examples/grpc/basics/pom.xml | 78 --- .../grpc/examples/basics/HealthClient.java | 70 --- .../helidon/grpc/examples/basics/Server.java | 105 ---- .../grpc/examples/basics/package-info.java | 20 - .../src/main/resources/application.yaml | 26 - .../src/main/resources/logging.properties | 34 -- examples/grpc/client-standalone/README.md | 18 - examples/grpc/client-standalone/pom.xml | 99 ---- .../client/standalone/StandaloneClient.java | 51 -- .../client/standalone/package-info.java | 20 - .../src/main/proto/strings.proto | 31 -- .../src/main/resources/logging.properties | 20 - examples/grpc/common/README.md | 1 - examples/grpc/common/pom.xml | 105 ---- .../grpc/examples/common/EchoService.java | 33 -- .../grpc/examples/common/GreetClient.java | 83 ---- .../grpc/examples/common/GreetService.java | 83 ---- .../examples/common/GreetServiceJava.java | 70 --- .../grpc/examples/common/StringClient.java | 284 ----------- .../grpc/examples/common/StringService.java | 92 ---- .../grpc/examples/common/package-info.java | 20 - .../grpc/common/src/main/proto/echo.proto | 30 -- .../grpc/common/src/main/proto/greet.proto | 40 -- .../grpc/common/src/main/proto/strings.proto | 31 -- examples/grpc/metrics/README.md | 159 ------ examples/grpc/metrics/pom.xml | 87 ---- .../helidon/grpc/examples/metrics/Server.java | 100 ---- .../grpc/examples/metrics/package-info.java | 22 - .../src/main/resources/application.yaml | 26 - .../src/main/resources/logging.properties | 34 -- .../grpc/microprofile/basic-client/README.md | 40 -- .../grpc/microprofile/basic-client/pom.xml | 83 ---- .../grpc/example/client/AsyncClient.java | 75 --- .../example/client/AsyncStringService.java | 83 ---- .../grpc/example/client/Client.java | 198 -------- .../grpc/example/client/StringService.java | 82 --- .../grpc/example/client/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 23 - .../src/main/resources/application.yaml | 25 - .../src/main/resources/logging.properties | 20 - .../basic-server-implicit/README.md | 32 -- .../basic-server-implicit/pom.xml | 87 ---- .../basic/implicit/AdditionalServices.java | 53 -- .../basic/implicit/AsyncStringService.java | 126 ----- .../example/basic/implicit/StringService.java | 123 ----- .../example/basic/implicit/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 23 - ...croprofile.grpc.server.spi.GrpcMpExtension | 17 - .../src/main/resources/application.yaml | 25 - .../src/main/resources/logging.properties | 20 - examples/grpc/microprofile/metrics/README.md | 101 ---- examples/grpc/microprofile/metrics/pom.xml | 91 ---- .../grpc/example/metrics/StringService.java | 152 ------ .../grpc/example/metrics/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 23 - .../src/main/resources/application.yaml | 25 - .../src/main/resources/logging.properties | 22 - examples/grpc/microprofile/pom.xml | 37 -- examples/grpc/opentracing/README.md | 32 -- examples/grpc/opentracing/pom.xml | 78 --- .../opentracing/ZipkinExampleMain.java | 88 ---- .../examples/opentracing/package-info.java | 20 - .../src/main/resources/application.yaml | 30 -- .../src/main/resources/logging.properties | 34 -- examples/grpc/pom.xml | 45 -- examples/grpc/security-abac/README.md | 35 -- examples/grpc/security-abac/pom.xml | 106 ---- .../examples/security/abac/AbacServer.java | 118 ----- .../security/abac/AbacServerFromConfig.java | 73 --- .../examples/security/abac/AtnProvider.java | 414 ---------------- .../security/abac/AtnProviderService.java | 43 -- .../security/abac/SecureStringClient.java | 53 -- .../examples/security/abac/package-info.java | 20 - .../grpc-security-abac/reflect-config.json | 11 - ...lidon.security.spi.SecurityProviderService | 17 - .../src/main/resources/application.yaml | 84 ---- .../src/main/resources/logging.properties | 19 - examples/grpc/security-outbound/README.md | 23 - examples/grpc/security-outbound/pom.xml | 102 ---- .../security/outbound/SecureGreetClient.java | 80 --- .../security/outbound/SecureServer.java | 341 ------------- .../security/outbound/package-info.java | 20 - .../src/main/resources/application.yaml | 36 -- .../src/main/resources/logging.properties | 35 -- examples/grpc/security/README.md | 33 -- examples/grpc/security/pom.xml | 98 ---- .../examples/security/SecureGreetClient.java | 106 ---- .../grpc/examples/security/SecureServer.java | 79 --- .../examples/security/SecureStringClient.java | 86 ---- .../grpc/examples/security/package-info.java | 20 - .../src/main/resources/application.yaml | 34 -- .../src/main/resources/logging.properties | 35 -- examples/health/basics/README.md | 23 - examples/health/basics/pom.xml | 79 --- .../helidon/examples/health/basics/Main.java | 76 --- .../examples/health/basics/package-info.java | 19 - examples/health/pom.xml | 35 -- examples/integrations/README.md | 1 - examples/integrations/cdi/README.md | 1 - .../cdi/datasource-hikaricp-h2/README.md | 19 - .../cdi/datasource-hikaricp-h2/pom.xml | 103 ---- .../hikaricp/jaxrs/TablesResource.java | 92 ---- .../hikaricp/jaxrs/package-info.java | 21 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 25 - .../cdi/datasource-hikaricp-mysql/README.md | 60 --- .../cdi/datasource-hikaricp-mysql/pom.xml | 104 ---- .../hikaricp/jaxrs/TablesResource.java | 92 ---- .../hikaricp/jaxrs/package-info.java | 21 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 25 - .../cdi/datasource-hikaricp/.dockerignore | 1 - .../cdi/datasource-hikaricp/Dockerfile | 44 -- .../cdi/datasource-hikaricp/README.md | 85 ---- .../cdi/datasource-hikaricp/pom.xml | 108 ---- .../hikaricp/jaxrs/TablesResource.java | 92 ---- .../hikaricp/jaxrs/package-info.java | 21 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 29 -- examples/integrations/cdi/jedis/.dockerignore | 1 - examples/integrations/cdi/jedis/Dockerfile | 44 -- examples/integrations/cdi/jedis/README.md | 55 --- examples/integrations/cdi/jedis/app.yaml | 77 --- examples/integrations/cdi/jedis/pom.xml | 102 ---- examples/integrations/cdi/jedis/redis.yaml | 50 -- .../jedis/jaxrs/RedisClientResource.java | 179 ------- .../examples/jedis/jaxrs/package-info.java | 21 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 22 - examples/integrations/cdi/jpa/README.md | 13 - examples/integrations/cdi/jpa/pom.xml | 187 ------- .../integrations/cdi/jpa/Greeting.java | 104 ---- .../cdi/jpa/HelloWorldApplication.java | 59 --- .../cdi/jpa/HelloWorldResource.java | 171 ------- .../cdi/jpa/JPAExceptionMapper.java | 67 --- .../integrations/cdi/jpa/package-info.java | 21 - .../jpa/src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 23 - .../main/resources/META-INF/persistence.xml | 52 -- examples/integrations/cdi/pokemons/README.md | 21 - examples/integrations/cdi/pokemons/pom.xml | 180 ------- .../integrations/cdi/pokemon/Pokemon.java | 109 ---- .../cdi/pokemon/PokemonResource.java | 133 ----- .../integrations/cdi/pokemon/PokemonType.java | 71 --- .../cdi/pokemon/PokemonTypeResource.java | 43 -- .../cdi/pokemon/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../main/resources/META-INF/init_script.sql | 25 - .../META-INF/microprofile-config.properties | 24 - .../main/resources/META-INF/persistence.xml | 34 -- .../integrations/cdi/pokemon/MainTest.java | 110 ----- examples/integrations/cdi/pom.xml | 42 -- examples/integrations/micrometer/mp/README.md | 75 --- examples/integrations/micrometer/mp/pom.xml | 102 ---- .../micrometer/mp/GreetResource.java | 136 ----- .../micrometer/mp/GreetingMessage.java | 58 --- .../micrometer/mp/GreetingProvider.java | 48 -- .../micrometer/mp/package-info.java | 20 - .../mp/src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 25 - .../mp/src/main/resources/application.yaml | 20 - .../mp/src/main/resources/logging.properties | 37 -- .../micrometer/mp/TestEndpoint.java | 66 --- examples/integrations/micrometer/pom.xml | 42 -- examples/integrations/micrometer/se/README.md | 89 ---- examples/integrations/micrometer/se/pom.xml | 93 ---- .../examples/micrometer/se/GreetService.java | 140 ------ .../micrometer/se/GreetingMessage.java | 87 ---- .../helidon/examples/micrometer/se/Main.java | 109 ---- .../examples/micrometer/se/package-info.java | 24 - .../se/src/main/resources/application.yaml | 24 - .../examples/micrometer/se/MainTest.java | 151 ------ .../integrations/micronaut/data/README.md | 146 ------ examples/integrations/micronaut/data/pom.xml | 157 ------ .../data/BeanValidationExceptionMapper.java | 39 -- .../micronaut/data/DbOwnerRepository.java | 48 -- .../micronaut/data/DbPetRepository.java | 54 -- .../micronaut/data/DbPopulateData.java | 62 --- .../micronaut/data/OwnerResource.java | 71 --- .../micronaut/data/PetResource.java | 72 --- .../micronaut/data/model/NameDTO.java | 35 -- .../micronaut/data/model/Owner.java | 66 --- .../micronaut/data/model/Pet.java | 92 ---- .../micronaut/data/model/package-info.java | 20 - .../micronaut/data/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 40 -- .../src/main/resources/logging.properties | 26 - .../micronaut/data/MicronautExampleTest.java | 74 --- examples/integrations/micronaut/pom.xml | 37 -- examples/integrations/microstream/README.md | 1 - .../microstream/greetings-mp/README.md | 21 - .../microstream/greetings-mp/pom.xml | 89 ---- .../greetings/mp/GreetResource.java | 111 ----- .../greetings/mp/GreetingMessage.java | 57 --- .../greetings/mp/GreetingProvider.java | 95 ---- .../greetings/mp/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 16 - .../mp/MicrostreamExampleGreetingsMpTest.java | 52 -- .../microstream/greetings-se/README.md | 24 - .../microstream/greetings-se/pom.xml | 97 ---- .../greetings/se/GreetingService.java | 188 ------- .../se/GreetingServiceMicrostreamContext.java | 87 ---- .../microstream/greetings/se/LogEntry.java | 51 -- .../microstream/greetings/se/Main.java | 105 ---- ...ostreamSingleThreadedExecutionContext.java | 163 ------ .../greetings/se/package-info.java | 20 - .../src/main/resources/application.yaml | 26 - .../se/MicrostreamExampleGreetingsSeTest.java | 81 --- examples/integrations/microstream/pom.xml | 38 -- .../integrations/neo4j/neo4j-mp/.dockerignore | 1 - .../integrations/neo4j/neo4j-mp/Dockerfile | 44 -- .../neo4j/neo4j-mp/Dockerfile.jlink | 41 -- .../neo4j/neo4j-mp/Dockerfile.native | 57 --- .../integrations/neo4j/neo4j-mp/README.md | 167 ------- examples/integrations/neo4j/neo4j-mp/app.yaml | 50 -- examples/integrations/neo4j/neo4j-mp/pom.xml | 141 ------ .../integrations/neo4j/mp/Neo4jResource.java | 64 --- .../integrations/neo4j/mp/domain/Actor.java | 63 --- .../integrations/neo4j/mp/domain/Movie.java | 100 ---- .../neo4j/mp/domain/MovieRepository.java | 99 ---- .../integrations/neo4j/mp/domain/Person.java | 81 --- .../neo4j/mp/domain/package-info.java | 19 - .../integrations/neo4j/mp/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 31 -- .../src/main/resources/logging.properties | 27 - .../integrations/neo4j/mp/MainTest.java | 126 ----- .../integrations/neo4j/mp/package-info.java | 20 - .../META-INF/microprofile-config.properties | 22 - .../integrations/neo4j/neo4j-se/.dockerignore | 1 - .../integrations/neo4j/neo4j-se/Dockerfile | 45 -- .../neo4j/neo4j-se/Dockerfile.jlink | 41 -- .../neo4j/neo4j-se/Dockerfile.native | 57 --- .../integrations/neo4j/neo4j-se/README.md | 183 ------- examples/integrations/neo4j/neo4j-se/app.yaml | 50 -- examples/integrations/neo4j/neo4j-se/pom.xml | 142 ------ .../examples/integrations/neo4j/se/Main.java | 138 ------ .../integrations/neo4j/se/MovieService.java | 54 -- .../integrations/neo4j/se/domain/Actor.java | 71 --- .../integrations/neo4j/se/domain/Movie.java | 101 ---- .../neo4j/se/domain/MovieRepository.java | 96 ---- .../integrations/neo4j/se/domain/Person.java | 79 --- .../neo4j/se/domain/package-info.java | 20 - .../integrations/neo4j/se/package-info.java | 23 - .../src/main/resources/application.yaml | 29 -- .../src/main/resources/logging.properties | 34 -- .../examples/quickstart/se/MainTest.java | 152 ------ .../examples/quickstart/se/package-info.java | 20 - examples/integrations/neo4j/pom.xml | 38 -- examples/integrations/oci/README.md | 1 - examples/integrations/oci/atp-cdi/README.md | 28 -- examples/integrations/oci/atp-cdi/pom.xml | 95 ---- .../integrations/oci/atp/cdi/AtpResource.java | 184 ------- .../oci/atp/cdi/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/application.yaml | 37 -- .../src/main/resources/logging.properties | 28 -- .../integrations/oci/atp-reactive/README.md | 28 -- .../integrations/oci/atp-reactive/pom.xml | 89 ---- .../oci/atp/reactive/AtpService.java | 198 -------- .../oci/atp/reactive/OciAtpMain.java | 80 --- .../oci/atp/reactive/OciResponseHandler.java | 50 -- .../oci/atp/reactive/package-info.java | 20 - .../src/main/resources/application.yaml | 32 -- .../src/main/resources/logging.properties | 28 -- .../integrations/oci/metrics-reactive/pom.xml | 74 --- .../telemetry/reactive/OciMetricsMain.java | 175 ------- .../oci/telemetry/reactive/package-info.java | 20 - .../src/main/resources/application.yaml | 23 - .../src/main/resources/logging.properties | 27 - .../oci/objectstorage-cdi/pom.xml | 87 ---- .../cdi/ObjectStorageCdiMain.java | 67 --- .../cdi/ObjectStorageResource.java | 159 ------ .../oci/objectstorage/cdi/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/application.yaml | 26 - .../src/main/resources/logging.properties | 28 -- .../oci/objectstorage-reactive/pom.xml | 73 --- .../reactive/ObjectStorageService.java | 223 --------- .../reactive/OciObjectStorageMain.java | 86 ---- .../objecstorage/reactive/package-info.java | 20 - .../src/main/resources/application.yaml | 26 - .../src/main/resources/logging.properties | 28 -- examples/integrations/oci/pom.xml | 45 -- examples/integrations/oci/vault-cdi/pom.xml | 101 ---- .../oci/vault/cdi/CryptoClientProducer.java | 45 -- .../oci/vault/cdi/ErrorHandlerProvider.java | 37 -- .../oci/vault/cdi/VaultCdiMain.java | 66 --- .../oci/vault/cdi/VaultResource.java | 247 ---------- .../oci/vault/cdi/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/application.yaml | 31 -- .../src/main/resources/logging.properties | 27 - .../integrations/oci/vault-reactive/pom.xml | 82 --- .../oci/vault/reactive/OciHandler.java | 51 -- .../oci/vault/reactive/OciVaultMain.java | 106 ---- .../oci/vault/reactive/VaultService.java | 184 ------- .../oci/vault/reactive/package-info.java | 20 - .../src/main/resources/application.yaml | 31 -- .../src/main/resources/logging.properties | 27 - examples/integrations/pom.xml | 43 -- examples/integrations/vault/hcp-cdi/README.md | 26 - examples/integrations/vault/hcp-cdi/pom.xml | 100 ---- .../vault/hcp/cdi/CubbyholeResource.java | 100 ---- .../vault/hcp/cdi/Kv1Resource.java | 134 ----- .../vault/hcp/cdi/Kv2Resource.java | 101 ---- .../vault/hcp/cdi/TransitResource.java | 231 --------- .../vault/hcp/cdi/VaultCdiMain.java | 66 --- .../vault/hcp/cdi/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/application.yaml | 27 - .../src/main/resources/logging.properties | 27 - .../integrations/vault/hcp-reactive/README.md | 26 - .../integrations/vault/hcp-reactive/pom.xml | 99 ---- .../vault/hcp/reactive/AppRoleExample.java | 127 ----- .../vault/hcp/reactive/CubbyholeService.java | 65 --- .../vault/hcp/reactive/K8sExample.java | 103 ---- .../vault/hcp/reactive/Kv1Service.java | 87 ---- .../vault/hcp/reactive/Kv2Service.java | 75 --- .../vault/hcp/reactive/ReactiveVaultMain.java | 149 ------ .../vault/hcp/reactive/TransitService.java | 193 -------- .../vault/hcp/reactive/VaultPolicy.java | 79 --- .../vault/hcp/reactive/package-info.java | 20 - .../src/main/resources/application.yaml | 59 --- .../src/main/resources/logging.properties | 27 - examples/integrations/vault/pom.xml | 38 -- examples/jbatch/README.md | 17 - examples/jbatch/pom.xml | 138 ------ .../helidon/jbatch/example/BatchResource.java | 93 ---- .../HelidonExecutorServiceProvider.java | 33 -- .../jbatch/example/jobs/MyBatchlet.java | 36 -- .../jbatch/example/jobs/MyInputRecord.java | 44 -- .../jbatch/example/jobs/MyItemProcessor.java | 31 -- .../jbatch/example/jobs/MyItemReader.java | 48 -- .../jbatch/example/jobs/MyItemWriter.java | 32 -- .../jbatch/example/jobs/MyOutputRecord.java | 45 -- .../jbatch/example/jobs/package-info.java | 20 - .../helidon/jbatch/example/package-info.java | 20 - .../resources/META-INF/batch-jobs/myJob.xml | 33 -- .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/helidon/serial-config.properties | 19 - .../META-INF/microprofile-config.properties | 22 - .../src/main/resources/logging.properties | 30 -- .../examples/jbatch/TestJBatchEndpoint.java | 76 --- examples/k8s/zipkin.yaml | 73 --- examples/logging/jul/README.md | 52 -- examples/logging/jul/pom.xml | 66 --- .../io/helidon/examples/logging/jul/Main.java | 87 ---- .../examples/logging/jul/package-info.java | 20 - .../jul/src/main/resources/logging.properties | 25 - examples/logging/log4j/README.md | 56 --- examples/logging/log4j/pom.xml | 78 --- .../helidon/examples/logging/log4j/Main.java | 126 ----- .../examples/logging/log4j/package-info.java | 20 - examples/logging/logback-aot/README.md | 60 --- .../logging/logback-aot/logback-runtime.xml | 60 --- examples/logging/logback-aot/pom.xml | 79 --- .../examples/logging/logback/aot/Main.java | 139 ------ .../logging/logback/aot/package-info.java | 21 - .../src/main/resources/logback.xml | 31 -- examples/logging/pom.xml | 44 -- examples/logging/slf4j/README.md | 45 -- examples/logging/slf4j/pom.xml | 78 --- .../helidon/examples/logging/slf4j/Main.java | 100 ---- .../examples/logging/slf4j/package-info.java | 20 - .../slf4j/src/main/resources/logback.xml | 31 -- examples/media/multipart/README.md | 23 - examples/media/multipart/pom.xml | 93 ---- .../examples/media/multipart/FileService.java | 102 ---- .../examples/media/multipart/FileStorage.java | 111 ----- .../examples/media/multipart/Main.java | 87 ---- .../media/multipart/package-info.java | 20 - .../src/main/resources/WEB/index.html | 59 --- .../media/multipart/FileServiceTest.java | 138 ------ examples/media/pom.xml | 41 -- examples/messaging/README.md | 55 --- .../messaging/docker/kafka/Dockerfile.kafka | 51 -- .../messaging/docker/kafka/init_topics.sh | 50 -- .../messaging/docker/kafka/start_kafka.sh | 49 -- .../docker/oracle-aq-18-xe/Dockerfile | 20 - .../docker/oracle-aq-18-xe/buildAndRun.sh | 102 ---- .../docker/oracle-aq-18-xe/examples.sql | 78 --- .../messaging/docker/oracle-aq-18-xe/init.sql | 62 --- .../docker/oracle-aq-18-xe/stopAndClean.sh | 20 - examples/messaging/jms-websocket-mp/README.md | 12 - examples/messaging/jms-websocket-mp/pom.xml | 76 --- .../messaging/mp/MsgProcessingBean.java | 121 ----- .../messaging/mp/SendingResource.java | 56 --- .../messaging/mp/WebSocketEndpoint.java | 95 ---- .../examples/messaging/mp/package-info.java | 21 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/WEB/favicon.ico | Bin 1230 -> 0 bytes .../src/main/resources/WEB/img/arrow-1.png | Bin 18222 -> 0 bytes .../src/main/resources/WEB/img/arrow-2.png | Bin 31965 -> 0 bytes .../src/main/resources/WEB/img/cloud.png | Bin 2104 -> 0 bytes .../src/main/resources/WEB/img/frank.png | Bin 10516 -> 0 bytes .../src/main/resources/WEB/index.html | 127 ----- .../src/main/resources/WEB/main.css | 172 ------- .../src/main/resources/application.yaml | 49 -- .../src/main/resources/logging.properties | 34 -- examples/messaging/jms-websocket-se/README.md | 12 - examples/messaging/jms-websocket-se/pom.xml | 86 ---- .../helidon/examples/messaging/se/Main.java | 113 ----- .../examples/messaging/se/SendingService.java | 95 ---- .../messaging/se/WebSocketEndpoint.java | 103 ---- .../examples/messaging/se/package-info.java | 20 - .../src/main/resources/WEB/favicon.ico | Bin 1230 -> 0 bytes .../src/main/resources/WEB/img/arrow-1.png | Bin 18222 -> 0 bytes .../src/main/resources/WEB/img/arrow-2.png | Bin 31965 -> 0 bytes .../src/main/resources/WEB/img/cloud.png | Bin 2104 -> 0 bytes .../src/main/resources/WEB/img/frank.png | Bin 10516 -> 0 bytes .../src/main/resources/WEB/index.html | 127 ----- .../src/main/resources/WEB/main.css | 172 ------- .../src/main/resources/application.yaml | 28 -- .../src/main/resources/logging.properties | 34 -- .../messaging/kafka-websocket-mp/README.md | 11 - examples/messaging/kafka-websocket-mp/pom.xml | 81 --- .../messaging/mp/MsgProcessingBean.java | 103 ---- .../messaging/mp/SendingResource.java | 57 --- .../messaging/mp/WebSocketEndpoint.java | 95 ---- .../examples/messaging/mp/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 36 -- .../src/main/resources/WEB/favicon.ico | Bin 1230 -> 0 bytes .../src/main/resources/WEB/img/arrow-1.png | Bin 18222 -> 0 bytes .../src/main/resources/WEB/img/arrow-2.png | Bin 31965 -> 0 bytes .../src/main/resources/WEB/img/cloud.png | Bin 2104 -> 0 bytes .../src/main/resources/WEB/img/frank.png | Bin 10516 -> 0 bytes .../src/main/resources/WEB/index.html | 127 ----- .../src/main/resources/WEB/main.css | 172 ------- .../src/main/resources/logging.properties | 32 -- .../messaging/kafka-websocket-se/README.md | 12 - examples/messaging/kafka-websocket-se/pom.xml | 82 --- .../helidon/examples/messaging/se/Main.java | 99 ---- .../examples/messaging/se/SendingService.java | 94 ---- .../messaging/se/WebSocketEndpoint.java | 106 ---- .../examples/messaging/se/package-info.java | 20 - .../src/main/resources/WEB/favicon.ico | Bin 1230 -> 0 bytes .../src/main/resources/WEB/img/arrow-1.png | Bin 18222 -> 0 bytes .../src/main/resources/WEB/img/arrow-2.png | Bin 31965 -> 0 bytes .../src/main/resources/WEB/img/cloud.png | Bin 2104 -> 0 bytes .../src/main/resources/WEB/img/frank.png | Bin 10516 -> 0 bytes .../src/main/resources/WEB/index.html | 127 ----- .../src/main/resources/WEB/main.css | 172 ------- .../src/main/resources/application.yaml | 28 -- .../src/main/resources/logging.properties | 34 -- examples/messaging/kafkaConsume.sh | 29 -- examples/messaging/kafkaProduce.sh | 29 -- examples/messaging/kafkaRun.sh | 36 -- .../oracle-aq-websocket-mp/README.md | 12 - .../messaging/oracle-aq-websocket-mp/pom.xml | 77 --- .../messaging/mp/MsgProcessingBean.java | 131 ----- .../messaging/mp/SendingResource.java | 56 --- .../messaging/mp/WebSocketEndpoint.java | 95 ---- .../examples/messaging/mp/package-info.java | 21 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 52 -- .../src/main/resources/WEB/favicon.ico | Bin 1230 -> 0 bytes .../src/main/resources/WEB/img/arrow-1.png | Bin 18222 -> 0 bytes .../src/main/resources/WEB/img/arrow-2.png | Bin 31965 -> 0 bytes .../src/main/resources/WEB/img/cloud.png | Bin 2104 -> 0 bytes .../src/main/resources/WEB/img/frank.png | Bin 10516 -> 0 bytes .../src/main/resources/WEB/index.html | 127 ----- .../src/main/resources/WEB/main.css | 172 ------- .../src/main/resources/logging.properties | 34 -- examples/messaging/pom.xml | 45 -- examples/messaging/weblogic-jms-mp/README.md | 24 - .../weblogic-jms-mp/buildAndRunWeblogic.sh | 53 -- .../weblogic-jms-mp/extractThinClientLib.sh | 22 - examples/messaging/weblogic-jms-mp/pom.xml | 88 ---- .../examples/messaging/mp/FrankResource.java | 94 ---- .../examples/messaging/mp/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 24 - .../src/main/resources/WEB/favicon.ico | Bin 1230 -> 0 bytes .../src/main/resources/WEB/img/arrow-1.png | Bin 18222 -> 0 bytes .../src/main/resources/WEB/img/arrow-2.png | Bin 31965 -> 0 bytes .../src/main/resources/WEB/img/cloud.png | Bin 2104 -> 0 bytes .../src/main/resources/WEB/img/frank.png | Bin 10516 -> 0 bytes .../src/main/resources/WEB/index.html | 101 ---- .../src/main/resources/WEB/main.css | 171 ------- .../src/main/resources/application.yaml | 42 -- .../src/main/resources/logging.properties | 35 -- .../weblogic-jms-mp/weblogic/Dockerfile | 54 -- .../container-scripts/create-wls-domain.py | 104 ---- .../createAndStartEmptyDomain.sh | 87 ---- .../container-scripts/get_healthcheck_url.sh | 22 - .../container-scripts/setupTestJMSQueue.py | 115 ----- .../weblogic/properties/domain.properties | 35 -- .../properties/domain_security.properties | 18 - examples/metrics/exemplar/README.md | 68 --- examples/metrics/exemplar/pom.xml | 116 ----- .../metrics/exemplar/GreetService.java | 195 -------- .../examples/metrics/exemplar/Main.java | 156 ------ .../metrics/exemplar/package-info.java | 24 - .../src/main/resources/application.yaml | 24 - .../src/main/resources/logging.properties | 34 -- .../examples/metrics/exemplar/MainTest.java | 215 -------- .../exemplar/src/test/resources/test-app.yaml | 29 -- examples/metrics/filtering/mp/pom.xml | 103 ---- .../metrics/filtering/mp/GreetResource.java | 110 ----- .../metrics/filtering/mp/GreetingMessage.java | 57 --- .../filtering/mp/GreetingProvider.java | 48 -- .../metrics/filtering/mp/package-info.java | 20 - .../mp/src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 25 - .../mp/src/main/resources/logging.properties | 30 -- .../metrics/filtering/mp/MainTest.java | 55 --- examples/metrics/filtering/pom.xml | 38 -- examples/metrics/filtering/se/pom.xml | 111 ----- .../metrics/filtering/se/GreetService.java | 198 -------- .../examples/metrics/filtering/se/Main.java | 116 ----- .../metrics/filtering/se/package-info.java | 19 - .../se/src/main/resources/application.yaml | 28 -- .../se/src/main/resources/logging.properties | 34 -- .../metrics/filtering/se/MainTest.java | 132 ----- .../metrics/http-status-count-se/README.md | 102 ---- examples/metrics/http-status-count-se/pom.xml | 94 ---- .../se/httpstatuscount/GreetService.java | 150 ------ .../HttpStatusMetricService.java | 96 ---- .../examples/se/httpstatuscount/Main.java | 108 ---- .../httpstatuscount/SimpleGreetService.java | 89 ---- .../se/httpstatuscount/package-info.java | 19 - .../src/main/resources/application.yaml | 24 - .../src/main/resources/logging.properties | 34 -- .../examples/se/httpstatuscount/MainTest.java | 136 ----- .../se/httpstatuscount/StatusService.java | 49 -- .../se/httpstatuscount/StatusTest.java | 149 ------ .../src/test/resources/application.yaml | 26 - examples/metrics/kpi/README.md | 122 ----- examples/metrics/kpi/pom.xml | 111 ----- .../examples/metrics/kpi/GreetService.java | 195 -------- .../io/helidon/examples/metrics/kpi/Main.java | 138 ------ .../examples/metrics/kpi/package-info.java | 24 - .../kpi/src/main/resources/application.yaml | 28 -- .../kpi/src/main/resources/logging.properties | 34 -- .../examples/metrics/kpi/MainTest.java | 136 ----- examples/metrics/pom.xml | 41 -- examples/microprofile/README.md | 3 - .../microprofile/bean-validation/README.md | 39 -- examples/microprofile/bean-validation/pom.xml | 90 ---- .../bean/validation/ValidEmailResource.java | 70 --- .../bean/validation/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 19 - .../src/main/resources/logging.properties | 30 -- .../validation/TestValidationEndpoint.java | 68 --- examples/microprofile/cors/README.md | 126 ----- examples/microprofile/cors/pom.xml | 102 ---- .../examples/cors/GreetResource.java | 151 ------ .../examples/cors/GreetingMessage.java | 58 --- .../examples/cors/GreetingProvider.java | 48 -- .../examples/cors/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 22 - .../src/main/resources/logging.properties | 30 -- .../microprofile/examples/cors/TestCORS.java | 231 --------- .../src/test/resources/logging.properties | 39 -- examples/microprofile/graphql/README.md | 265 ---------- examples/microprofile/graphql/pom.xml | 68 --- .../helidon/examples/graphql/basics/Task.java | 133 ----- .../examples/graphql/basics/TaskApi.java | 149 ------ .../graphql/basics/TaskNotFoundException.java | 30 -- .../examples/graphql/basics/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 20 - .../src/main/resources/logging.properties | 24 - .../graphql/src/main/resources/web/index.html | 23 - .../hello-world-explicit/README.md | 20 - .../microprofile/hello-world-explicit/pom.xml | 76 --- .../explicit/HelloWorldResource.java | 97 ---- .../example/helloworld/explicit/Main.java | 48 -- .../helloworld/explicit/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 23 - .../src/main/resources/logging.properties | 24 - .../hello-world-implicit/README.md | 20 - .../microprofile/hello-world-implicit/pom.xml | 88 ---- .../helloworld/implicit/AnotherResource.java | 107 ---- .../implicit/HelloWorldResource.java | 113 ----- .../implicit/cdi/LoggerQualifier.java | 34 -- .../helloworld/implicit/cdi/RequestId.java | 33 -- .../implicit/cdi/RequestIdProducer.java | 27 - .../implicit/cdi/ResourceProducer.java | 54 -- .../helloworld/implicit/cdi/package-info.java | 20 - .../helloworld/implicit/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 26 - .../src/main/resources/logging.properties | 20 - .../implicit/ImplicitHelloWorldTest.java | 56 --- .../http-status-count-mp/README.md | 78 --- .../http-status-count-mp/app.yaml | 32 -- .../microprofile/http-status-count-mp/pom.xml | 115 ----- .../mp/httpstatuscount/GreetResource.java | 127 ----- .../mp/httpstatuscount/GreetingMessage.java | 56 --- .../mp/httpstatuscount/GreetingProvider.java | 48 -- .../HttpStatusMetricFilter.java | 82 --- .../httpstatuscount/SimpleGreetResource.java | 89 ---- .../mp/httpstatuscount/package-info.java | 19 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 27 - .../META-INF/native-image/reflect-config.json | 1 - .../src/main/resources/application.yaml | 16 - .../src/main/resources/logging.properties | 37 -- .../examples/mp/httpstatuscount/MainTest.java | 114 ----- .../mp/httpstatuscount/StatusResource.java | 51 -- .../mp/httpstatuscount/StatusTest.java | 101 ---- .../src/test/resources/application.yaml | 17 - examples/microprofile/idcs/README.md | 54 -- examples/microprofile/idcs/pom.xml | 85 ---- .../security/idcs/IdcsApplication.java | 35 -- .../microprofile/security/idcs/IdcsMain.java | 46 -- .../security/idcs/IdcsResource.java | 83 ---- .../security/idcs/ReactiveService.java | 51 -- .../security/idcs/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../idcs/src/main/resources/WEB/resource.html | 32 -- .../idcs/src/main/resources/application.yaml | 63 --- .../src/main/resources/logging.properties | 22 - examples/microprofile/lra/README.md | 49 -- examples/microprofile/lra/pom.xml | 85 ---- .../example/lra/LRAExampleResource.java | 99 ---- .../example/lra/package-info.java | 21 - .../lra/src/main/resources/META-INF/beans.xml | 25 - .../lra/src/main/resources/application.yaml | 19 - .../lra/src/main/resources/logging.properties | 19 - examples/microprofile/messaging-sse/README.md | 18 - examples/microprofile/messaging-sse/pom.xml | 93 ---- .../sse/MessagingExampleResource.java | 72 --- .../messaging/sse/MsgProcessingBean.java | 121 ----- .../example/messaging/sse/package-info.java | 21 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/WEB/favicon.ico | Bin 1230 -> 0 bytes .../src/main/resources/WEB/img/arrow-1.png | Bin 18222 -> 0 bytes .../src/main/resources/WEB/img/arrow-2.png | Bin 31965 -> 0 bytes .../src/main/resources/WEB/img/cloud.png | Bin 2104 -> 0 bytes .../src/main/resources/WEB/img/frank.png | Bin 10516 -> 0 bytes .../src/main/resources/WEB/index.html | 120 ----- .../src/main/resources/WEB/main.css | 172 ------- .../src/main/resources/application.yaml | 18 - .../src/main/resources/logging.properties | 20 - examples/microprofile/multipart/README.md | 22 - examples/microprofile/multipart/pom.xml | 89 ---- .../microprofile/multipart/FileService.java | 104 ---- .../microprofile/multipart/FileStorage.java | 104 ---- .../multipart/MultiPartFeatureProvider.java | 34 -- .../microprofile/multipart/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 23 - .../src/main/resources/WEB/index.html | 59 --- .../src/main/resources/logging.properties | 37 -- .../multipart/FileServiceTest.java | 115 ----- examples/microprofile/multiport/README.md | 40 -- examples/microprofile/multiport/pom.xml | 93 ---- .../multiport/PrivateApplication.java | 35 -- .../multiport/PrivateResource.java | 39 -- .../multiport/PublicApplication.java | 32 -- .../multiport/PublicResource.java | 39 -- .../microprofile/multiport/package-info.java | 19 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/application.yaml | 32 -- .../microprofile/multiport/MainTest.java | 160 ------ examples/microprofile/oidc/README.md | 27 - examples/microprofile/oidc/pom.xml | 80 --- .../microprofile/security/oidc/OidcMain.java | 53 -- .../security/oidc/OidcResource.java | 43 -- .../security/oidc/package-info.java | 19 - .../src/main/resources/META-INF/beans.xml | 25 - .../oidc/src/main/resources/application.yaml | 54 -- .../src/main/resources/logging.properties | 28 -- examples/microprofile/openapi-basic/README.md | 33 -- examples/microprofile/openapi-basic/pom.xml | 92 ---- .../examples/openapi/basic/GreetResource.java | 147 ------ .../openapi/basic/GreetingMessage.java | 57 --- .../openapi/basic/GreetingProvider.java | 48 -- .../basic/internal/SimpleAPIFilter.java | 40 -- .../basic/internal/SimpleAPIModelReader.java | 74 --- .../openapi/basic/internal/package-info.java | 20 - .../examples/openapi/basic/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 25 - .../src/main/resources/logging.properties | 37 -- .../examples/openapi/basic/MainTest.java | 133 ----- .../META-INF/microprofile-config.properties | 22 - examples/microprofile/pom.xml | 53 -- examples/microprofile/security/README.md | 28 -- examples/microprofile/security/pom.xml | 87 ---- .../example/security/HelloWorldResource.java | 104 ---- .../microprofile/example/security/Main.java | 48 -- .../example/security/OtherApp.java | 38 -- .../example/security/StaticContentApp.java | 37 -- .../example/security/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 26 - .../src/main/resources/WEB/resource.html | 32 -- .../src/main/resources/application.yaml | 40 -- .../src/main/resources/logging.properties | 20 - .../microprofile/static-content/README.md | 20 - examples/microprofile/static-content/pom.xml | 122 ----- .../example/staticc/HelloWorldResource.java | 44 -- .../microprofile/example/staticc/Main.java | 60 --- .../example/staticc/package-info.java | 20 - .../src/main/java/module-info.java.txt | 31 -- .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 27 - .../src/main/resources/WEB/resource.html | 33 -- .../src/main/resources/logging.properties | 26 - .../example/staticc/StaticContentTest.java | 100 ---- .../src/test/resources/logging.properties | 19 - examples/microprofile/tls/README.md | 16 - examples/microprofile/tls/pom.xml | 83 ---- .../example/tls/GreetResource.java | 49 -- .../microprofile/example/tls/Main.java | 41 -- .../example/tls/package-info.java | 20 - .../tls/src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 28 -- .../tls/src/main/resources/logging.properties | 28 -- .../tls/src/main/resources/server.p12 | Bin 4133 -> 0 bytes .../microprofile/example/tls/TlsTest.java | 83 ---- .../META-INF/microprofile-config.properties | 20 - examples/microprofile/websocket/README.md | 15 - examples/microprofile/websocket/pom.xml | 92 ---- .../websocket/MessageBoardEndpoint.java | 114 ----- .../example/websocket/MessageQueue.java | 67 --- .../websocket/MessageQueueResource.java | 48 -- .../example/websocket/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/WEB/index.html | 81 --- .../src/main/resources/application.yaml | 22 - .../src/main/resources/logging.properties | 20 - .../example/websocket/MessageBoardTest.java | 124 ----- examples/openapi-tools/README.md | 3 - examples/openapi-tools/pom.xml | 38 -- .../openapi-tools/quickstart-mp/README.md | 280 ----------- .../quickstart-mp/mp-client/README.md | 7 - .../quickstart-mp/mp-client/docs/Message.md | 15 - .../mp-client/docs/MessageApi.md | 108 ---- .../quickstart-mp/mp-client/pom.xml | 137 ------ .../client/JavaTimeFormatter.java | 74 --- .../client/RFC3339DateFormat.java | 61 --- .../openapitools/client/api/ApiException.java | 34 -- .../client/api/ApiExceptionMapper.java | 36 -- .../openapitools/client/api/MessageApi.java | 62 --- .../client/api/MessageService.java | 80 --- .../openapitools/client/api/package-info.java | 20 - .../openapitools/client/model/Message.java | 95 ---- .../client/model/package-info.java | 20 - .../org/openapitools/client/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 27 - .../META-INF/microprofile-config.properties | 19 - .../client/api/MessageApiTest.java | 89 ---- .../client/model/MessageTest.java | 58 --- .../quickstart-mp/mp-server/README.md | 36 -- .../quickstart-mp/mp-server/pom.xml | 134 ----- .../server/JavaTimeFormatter.java | 74 --- .../server/RFC3339DateFormat.java | 54 -- .../openapitools/server/RestApplication.java | 27 - .../server/api/MessageService.java | 47 -- .../server/api/MessageServiceImpl.java | 72 --- .../openapitools/server/api/package-info.java | 20 - .../openapitools/server/model/Message.java | 95 ---- .../server/model/package-info.java | 20 - .../org/openapitools/server/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 27 - .../META-INF/microprofile-config.properties | 27 - .../src/main/resources/META-INF/openapi.yml | 104 ---- .../src/main/resources/logging.properties | 34 -- .../server/model/MessageTest.java | 52 -- examples/openapi-tools/quickstart-mp/pom.xml | 41 -- .../openapi-tools/quickstart-se/README.md | 387 --------------- examples/openapi-tools/quickstart-se/pom.xml | 41 -- .../quickstart-se/se-client/README.md | 24 - .../quickstart-se/se-client/docs/Message.md | 15 - .../se-client/docs/MessageApi.md | 199 -------- .../quickstart-se/se-client/pom.xml | 133 ----- .../org/openapitools/client/ApiClient.java | 242 --------- .../org/openapitools/client/ApiResponse.java | 47 -- .../openapitools/client/ApiResponseBase.java | 49 -- .../java/org/openapitools/client/Main.java | 90 ---- .../java/org/openapitools/client/Pair.java | 60 --- .../client/RFC3339DateFormat.java | 61 --- .../openapitools/client/api/MessageApi.java | 52 -- .../client/api/MessageApiImpl.java | 166 ------- .../client/api/MessageService.java | 88 ---- .../openapitools/client/api/ResponseType.java | 47 -- .../openapitools/client/api/package-info.java | 20 - .../openapitools/client/model/Message.java | 96 ---- .../client/model/package-info.java | 20 - .../org/openapitools/client/package-info.java | 20 - .../src/main/resources/application.yaml | 19 - .../client/api/MessageApiTest.java | 109 ---- .../client/model/MessageTest.java | 58 --- .../quickstart-se/se-server/README.md | 36 -- .../quickstart-se/se-server/pom.xml | 154 ------ .../java/org/openapitools/server/Main.java | 109 ---- .../server/RFC3339DateFormat.java | 54 -- .../openapitools/server/api/JsonProvider.java | 36 -- .../server/api/MessageService.java | 66 --- .../server/api/MessageServiceImpl.java | 69 --- .../server/api/ValidatorUtils.java | 128 ----- .../openapitools/server/api/package-info.java | 20 - .../openapitools/server/model/Message.java | 100 ---- .../server/model/package-info.java | 20 - .../org/openapitools/server/package-info.java | 20 - .../src/main/resources/META-INF/openapi.yml | 104 ---- .../src/main/resources/application.yaml | 19 - .../src/main/resources/logging.properties | 34 -- .../org/openapitools/server/MainTest.java | 63 --- .../server/model/MessageTest.java | 51 -- examples/openapi-tools/quickstart.yaml | 96 ---- examples/openapi/README.md | 36 -- examples/openapi/pom.xml | 100 ---- .../examples/openapi/GreetService.java | 126 ----- .../examples/openapi/GreetingMessage.java | 87 ---- .../io/helidon/examples/openapi/Main.java | 104 ---- .../openapi/internal/SimpleAPIFilter.java | 40 -- .../internal/SimpleAPIModelReader.java | 74 --- .../openapi/internal/package-info.java | 20 - .../examples/openapi/package-info.java | 24 - .../src/main/resources/META-INF/openapi.yml | 79 --- .../src/main/resources/application.yaml | 29 -- .../src/main/resources/logging.properties | 35 -- .../io/helidon/examples/openapi/MainTest.java | 146 ------ examples/pom.xml | 81 --- examples/quickstarts/README.md | 8 - .../helidon-quickstart-mp/.dockerignore | 1 - .../helidon-quickstart-mp/.gitignore | 16 - .../helidon-quickstart-mp/Dockerfile | 44 -- .../helidon-quickstart-mp/Dockerfile.jlink | 41 -- .../helidon-quickstart-mp/Dockerfile.native | 57 --- .../helidon-quickstart-mp/README.md | 166 ------- .../helidon-quickstart-mp/app.yaml | 57 --- .../helidon-quickstart-mp/build.gradle | 105 ---- .../quickstarts/helidon-quickstart-mp/pom.xml | 89 ---- .../helidon-quickstart-mp/settings.gradle | 17 - .../examples/quickstart/mp/GreetResource.java | 135 ----- .../quickstart/mp/GreetingMessage.java | 57 --- .../quickstart/mp/GreetingProvider.java | 48 -- .../examples/quickstart/mp/package-info.java | 27 - .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 25 - .../src/main/resources/logging.properties | 40 -- .../examples/quickstart/mp/MainTest.java | 79 --- .../META-INF/microprofile-config.properties | 22 - .../helidon-quickstart-se/.dockerignore | 1 - .../helidon-quickstart-se/.gitignore | 16 - .../helidon-quickstart-se/Dockerfile | 45 -- .../helidon-quickstart-se/Dockerfile.jlink | 41 -- .../helidon-quickstart-se/Dockerfile.native | 57 --- .../helidon-quickstart-se/README.md | 165 ------- .../helidon-quickstart-se/app.yaml | 57 --- .../helidon-quickstart-se/build.gradle | 89 ---- .../quickstarts/helidon-quickstart-se/pom.xml | 99 ---- .../helidon-quickstart-se/settings.gradle | 17 - .../examples/quickstart/se/GreetService.java | 156 ------ .../helidon/examples/quickstart/se/Main.java | 101 ---- .../examples/quickstart/se/package-info.java | 24 - .../src/main/resources/application.yaml | 26 - .../src/main/resources/logging.properties | 34 -- .../examples/quickstart/se/MainTest.java | 110 ----- .../src/test/resources/config-profile.yaml | 23 - .../.dockerignore | 1 - .../.gitignore | 16 - .../Dockerfile | 44 -- .../Dockerfile.jlink | 41 -- .../Dockerfile.native | 57 --- .../README.md | 166 ------- .../helidon-standalone-quickstart-mp/app.yaml | 57 --- .../helidon-standalone-quickstart-mp/pom.xml | 261 ---------- .../examples/quickstart/mp/GreetResource.java | 127 ----- .../quickstart/mp/GreetingMessage.java | 57 --- .../quickstart/mp/GreetingProvider.java | 48 -- .../examples/quickstart/mp/package-info.java | 28 -- .../src/main/resources/META-INF/beans.xml | 25 - .../META-INF/microprofile-config.properties | 25 - .../src/main/resources/logging.properties | 41 -- .../examples/quickstart/mp/MainTest.java | 79 --- .../.dockerignore | 1 - .../.gitignore | 16 - .../Dockerfile | 45 -- .../Dockerfile.jlink | 41 -- .../Dockerfile.native | 57 --- .../README.md | 166 ------- .../helidon-standalone-quickstart-se/app.yaml | 57 --- .../helidon-standalone-quickstart-se/pom.xml | 250 ---------- .../examples/quickstart/se/GreetService.java | 156 ------ .../helidon/examples/quickstart/se/Main.java | 101 ---- .../examples/quickstart/se/package-info.java | 24 - .../helidon-example-reflection-config.json | 1 - .../native-image/native-image.properties | 17 - .../src/main/resources/application.yaml | 26 - .../src/main/resources/logging.properties | 34 -- .../examples/quickstart/se/MainTest.java | 110 ----- .../src/test/resources/config-profile.yaml | 23 - examples/quickstarts/pom.xml | 39 -- examples/security/README.md | 4 - .../attribute-based-access-control/README.md | 10 - .../attribute-based-access-control/pom.xml | 90 ---- .../examples/abac/AbacApplication.java | 34 -- .../examples/abac/AbacExplicitResource.java | 139 ------ .../examples/abac/AbacJerseyMain.java | 62 --- .../security/examples/abac/AbacResource.java | 77 --- .../security/examples/abac/AtnProvider.java | 151 ------ .../security/examples/abac/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/application.yaml | 88 ---- .../src/main/resources/logging.properties | 19 - .../basic-auth-with-static-content/README.md | 31 -- .../basic-auth-with-static-content/pom.xml | 108 ---- .../basic/BasicExampleBuilderMain.java | 143 ------ .../basic/BasicExampleConfigMain.java | 72 --- .../webserver/basic/BasicExampleUtil.java | 63 --- .../webserver/basic/package-info.java | 20 - .../src/main/resources/WEB/index.html | 43 -- .../src/main/resources/application.yaml | 60 --- .../src/main/resources/logging.properties | 21 - .../basic/BasicExampleBuilderTest.java | 46 -- .../basic/BasicExampleConfigTest.java | 46 -- .../webserver/basic/BasicExampleTest.java | 187 ------- examples/security/google-login/README.md | 25 - examples/security/google-login/pom.xml | 102 ---- .../examples/google/GoogleBuilderMain.java | 79 --- .../examples/google/GoogleConfigMain.java | 86 ---- .../security/examples/google/GoogleUtil.java | 67 --- .../examples/google/package-info.java | 20 - .../src/main/resources/WEB/index.html | 86 ---- .../resources/WEB/static/js/google-app.js | 47 -- .../src/main/resources/application.yaml | 50 -- .../src/main/resources/logging.properties | 19 - .../google/GoogleBuilderMainTest.java | 42 -- .../examples/google/GoogleConfigMainTest.java | 42 -- .../examples/google/GoogleMainTest.java | 75 --- examples/security/idcs-login/README.md | 76 --- examples/security/idcs-login/pom.xml | 133 ----- .../examples/idcs/IdcsBuilderMain.java | 109 ---- .../security/examples/idcs/IdcsMain.java | 93 ---- .../security/examples/idcs/IdcsUtil.java | 74 --- .../security/examples/idcs/package-info.java | 22 - .../src/main/resources/application.yaml | 66 --- .../src/main/resources/logging.properties | 25 - examples/security/jersey/README.md | 27 - examples/security/jersey/pom.xml | 97 ---- .../examples/jersey/JerseyBuilderMain.java | 130 ----- .../examples/jersey/JerseyConfigMain.java | 88 ---- .../jersey/JerseyProgrammaticMain.java | 84 ---- .../examples/jersey/JerseyResources.java | 163 ------ .../security/examples/jersey/JerseyUtil.java | 90 ---- .../examples/jersey/package-info.java | 23 - .../src/main/resources/application.yaml | 45 -- .../src/main/resources/logging.properties | 19 - .../jersey/JerseyBuilderMainTest.java | 40 -- .../examples/jersey/JerseyConfigMainTest.java | 40 -- .../examples/jersey/JerseyMainTest.java | 163 ------ .../jersey/JerseyProgrammaticMainTest.java | 40 -- .../security/nohttp-programmatic/README.md | 10 - examples/security/nohttp-programmatic/pom.xml | 62 --- .../examples/security/MyProvider.java | 133 ----- .../security/ProgrammaticSecurity.java | 157 ------ .../examples/security/package-info.java | 20 - .../src/main/resources/logging.properties | 19 - examples/security/outbound-override/README.md | 20 - examples/security/outbound-override/pom.xml | 93 ---- .../outbound/OutboundOverrideExample.java | 118 ----- .../outbound/OutboundOverrideJwtExample.java | 123 ----- .../outbound/OutboundOverrideUtil.java | 73 --- .../examples/outbound/package-info.java | 20 - .../main/resources/client-service-jwt.yaml | 63 --- .../src/main/resources/client-service.yaml | 41 -- .../main/resources/serving-service-jwt.yaml | 28 -- .../src/main/resources/serving-service.yaml | 33 -- .../src/main/resources/signing-jwk.json | 14 - .../src/main/resources/verifying-jwk.json | 14 - .../outbound/OutboundOverrideExampleTest.java | 84 ---- .../OutboundOverrideJwtExampleTest.java | 84 ---- examples/security/pom.xml | 51 -- examples/security/spi-examples/README.md | 17 - examples/security/spi-examples/pom.xml | 82 --- .../examples/spi/AtnProviderSync.java | 179 ------- .../examples/spi/AtzProviderSync.java | 46 -- .../security/examples/spi/Auditer.java | 45 -- .../examples/spi/OutboundProviderSync.java | 49 -- .../examples/spi/ProviderSelector.java | 77 --- .../security/examples/spi/package-info.java | 22 - .../examples/spi/AtnProviderSyncTest.java | 225 --------- .../examples/spi/AtzProviderSyncTest.java | 114 ----- .../security/examples/spi/AuditerTest.java | 66 --- .../spi/OutboundProviderSyncTest.java | 81 --- .../examples/spi/ProviderSelectorTest.java | 45 -- examples/security/vaults/README.md | 34 -- examples/security/vaults/pom.xml | 104 ---- .../security/vaults/DigestService.java | 59 --- .../security/vaults/EncryptionService.java | 57 --- .../security/vaults/SecretsService.java | 43 -- .../security/vaults/VaultsExampleMain.java | 112 ----- .../security/vaults/package-info.java | 20 - .../src/main/resources/application.yaml | 92 ---- .../src/main/resources/logging.properties | 27 - .../security/webserver-digest-auth/README.md | 30 -- .../security/webserver-digest-auth/pom.xml | 98 ---- .../digest/DigestExampleBuilderMain.java | 169 ------- .../digest/DigestExampleConfigMain.java | 71 --- .../webserver/digest/DigestExampleUtil.java | 78 --- .../webserver/digest/package-info.java | 23 - .../src/main/resources/application.yaml | 56 --- .../src/main/resources/logging.properties | 23 - .../digest/DigestExampleBuilderTest.java | 49 -- .../digest/DigestExampleConfigTest.java | 49 -- .../webserver/digest/DigestExampleTest.java | 198 -------- .../security/webserver-signatures/README.md | 29 -- .../security/webserver-signatures/pom.xml | 101 ---- .../SignatureExampleBuilderMain.java | 242 --------- .../SignatureExampleConfigMain.java | 123 ----- .../signatures/SignatureExampleUtil.java | 103 ---- .../examples/signatures/package-info.java | 22 - .../src/main/resources/keystore.p12 | Bin 2700 -> 0 bytes .../src/main/resources/service1.yaml | 83 ---- .../src/main/resources/service2.yaml | 75 --- .../SignatureExampleBuilderMainTest.java | 51 -- .../SignatureExampleConfigMainTest.java | 51 -- .../signatures/SignatureExampleTest.java | 116 ----- examples/todo-app/README.md | 41 -- examples/todo-app/backend/pom.xml | 164 ------ .../helidon/demo/todos/backend/DbService.java | 244 --------- .../todos/backend/JaxRsBackendResource.java | 178 ------- .../io/helidon/demo/todos/backend/Main.java | 82 --- .../io/helidon/demo/todos/backend/Todo.java | 260 ---------- .../demo/todos/backend/package-info.java | 20 - .../src/main/resources/META-INF/beans.xml | 25 - .../src/main/resources/application.yaml | 48 -- .../src/main/resources/logging.properties | 28 -- .../demo/todos/backend/BackendTests.java | 160 ------ .../src/test/resources/test-application.yaml | 40 -- examples/todo-app/cassandra/Dockerfile | 27 - examples/todo-app/cassandra/startup.sh | 42 -- examples/todo-app/frontend/pom.xml | 158 ------ .../todos/frontend/BackendServiceClient.java | 122 ----- .../io/helidon/demo/todos/frontend/Main.java | 158 ------ .../demo/todos/frontend/TodoService.java | 152 ------ .../demo/todos/frontend/package-info.java | 20 - .../src/main/resources/WEB/css/styles.css | 427 ---------------- .../src/main/resources/WEB/index.html | 91 ---- .../frontend/src/main/resources/WEB/js/app.js | 465 ------------------ .../src/main/resources/application.yaml | 60 --- .../src/main/resources/logging.properties | 28 -- .../demo/todos/frontend/TodoServiceTest.java | 191 ------- .../src/test/resources/application-test.yaml | 30 -- examples/todo-app/pom.xml | 44 -- examples/translator-app/README.md | 86 ---- examples/translator-app/backend/Dockerfile | 47 -- examples/translator-app/backend/app.yaml | 54 -- examples/translator-app/backend/pom.xml | 71 --- .../examples/translator/backend/Main.java | 76 --- .../backend/TranslatorBackendService.java | 178 ------- .../translator/backend/package-info.java | 20 - .../src/main/resources/logging.properties | 26 - examples/translator-app/frontend/Dockerfile | 48 -- examples/translator-app/frontend/app.yaml | 76 --- examples/translator-app/frontend/pom.xml | 112 ----- .../examples/translator/frontend/Main.java | 79 --- .../frontend/TranslatorFrontendService.java | 78 --- .../translator/frontend/package-info.java | 20 - .../src/main/resources/logging.properties | 26 - .../examples/translator/TranslatorTest.java | 95 ---- examples/translator-app/pom.xml | 42 -- examples/webclient/pom.xml | 37 -- examples/webclient/standalone/README.md | 32 -- examples/webclient/standalone/pom.xml | 93 ---- .../webclient/standalone/ClientMain.java | 198 -------- .../webclient/standalone/GreetService.java | 170 ------- .../webclient/standalone/ServerMain.java | 98 ---- .../webclient/standalone/package-info.java | 19 - .../src/main/resources/application.yaml | 26 - .../main/resources/full-webclient-config.yaml | 75 --- .../webclient/standalone/ClientMainTest.java | 147 ------ examples/webserver/README.md | 3 - examples/webserver/basics/README.md | 45 -- examples/webserver/basics/pom.xml | 89 ---- .../webserver/examples/basics/Catalog.java | 42 -- .../examples/basics/HelloWorldResource.java | 37 -- .../webserver/examples/basics/Main.java | 384 --------------- .../webserver/examples/basics/Name.java | 90 ---- .../webserver/examples/basics/NameReader.java | 59 --- .../examples/basics/package-info.java | 20 - .../src/main/resources/static/index.html | 28 -- .../webserver/examples/basics/MainTest.java | 167 ------- examples/webserver/comment-aas/README.md | 20 - .../webserver/comment-aas/etc/add-comment | 38 -- .../webserver/comment-aas/etc/config.yaml | 17 - .../webserver/comment-aas/etc/create-etcd | 43 -- .../webserver/comment-aas/etc/get-etcd-config | 22 - .../webserver/comment-aas/etc/list-comments | 38 -- .../webserver/comment-aas/etc/put-etcd-config | 27 - examples/webserver/comment-aas/etc/start-etcd | 19 - .../comment-aas/etc/stop-comment-service | 33 -- examples/webserver/comment-aas/etc/stop-etcd | 19 - .../webserver/comment-aas/etc/switch-user | 26 - examples/webserver/comment-aas/pom.xml | 87 ---- .../examples/comments/CommentsService.java | 121 ----- .../webserver/examples/comments/Main.java | 94 ---- .../examples/comments/ProfanityDetector.java | 44 -- .../examples/comments/ProfanityException.java | 63 --- .../examples/comments/package-info.java | 23 - .../src/main/resources/application.yaml | 21 - .../comments/CommentsServiceTest.java | 82 --- .../webserver/examples/comments/MainTest.java | 51 -- examples/webserver/fault-tolerance/pom.xml | 85 ---- .../examples/faulttolerance/FtService.java | 168 ------- .../examples/faulttolerance/Main.java | 74 --- .../examples/faulttolerance/package-info.java | 20 - .../src/main/resources/logging.properties | 22 - .../examples/faulttolerance/MainTest.java | 198 -------- examples/webserver/jersey/README.md | 18 - examples/webserver/jersey/pom.xml | 81 --- .../webserver/examples/jersey/HelloWorld.java | 39 -- .../webserver/examples/jersey/Main.java | 79 --- .../examples/jersey/package-info.java | 23 - .../src/main/resources/logging.properties | 26 - .../examples/jersey/HelloWorldTest.java | 73 --- examples/webserver/multiport/README.md | 38 -- examples/webserver/multiport/pom.xml | 98 ---- .../examples/webserver/multiport/Main.java | 126 ----- .../webserver/multiport/package-info.java | 19 - .../src/main/resources/application.yaml | 25 - .../src/main/resources/logging.properties | 34 -- .../webserver/multiport/MainTest.java | 143 ------ .../src/test/resources/application-test.yaml | 25 - examples/webserver/mutual-tls/README.md | 26 - .../mutual-tls/automatic-store-generator.sh | 163 ------ examples/webserver/mutual-tls/pom.xml | 83 ---- .../examples/mtls/ClientBuilderMain.java | 83 ---- .../examples/mtls/ClientConfigMain.java | 68 --- .../examples/mtls/ServerBuilderMain.java | 108 ---- .../examples/mtls/ServerConfigMain.java | 85 ---- .../webserver/examples/mtls/package-info.java | 21 - .../src/main/resources/application.yaml | 49 -- .../mutual-tls/src/main/resources/client.p12 | Bin 4181 -> 0 bytes .../mutual-tls/src/main/resources/server.p12 | Bin 4133 -> 0 bytes .../examples/mtls/MutualTlsExampleTest.java | 64 --- .../src/test/resources/application-test.yaml | 49 -- examples/webserver/opentracing/Dockerfile | 47 -- examples/webserver/opentracing/README.md | 41 -- examples/webserver/opentracing/pom.xml | 92 ---- .../webserver/examples/opentracing/Main.java | 81 --- .../examples/opentracing/package-info.java | 22 - .../src/main/resources/logging.properties | 26 - examples/webserver/pom.xml | 49 -- examples/webserver/static-content/README.md | 13 - examples/webserver/static-content/pom.xml | 86 ---- .../staticcontent/CounterService.java | 60 --- .../examples/staticcontent/Main.java | 75 --- .../examples/staticcontent/package-info.java | 25 - .../src/main/resources/WEB/css/app.css | 19 - .../src/main/resources/WEB/index.html | 88 ---- .../src/main/resources/WEB/js/app.js | 22 - examples/webserver/streaming/README.md | 19 - examples/webserver/streaming/pom.xml | 78 --- .../webserver/examples/streaming/Main.java | 61 --- .../examples/streaming/StreamingService.java | 106 ---- .../examples/streaming/package-info.java | 23 - .../src/main/resources/large-file.bin | Bin 12288 -> 0 bytes examples/webserver/threadpool/README.md | 67 --- examples/webserver/threadpool/pom.xml | 97 ---- .../webserver/threadpool/GreetService.java | 205 -------- .../examples/webserver/threadpool/Main.java | 106 ---- .../webserver/threadpool/package-info.java | 19 - .../src/main/resources/application.yaml | 29 -- .../src/main/resources/logging.properties | 38 -- .../webserver/threadpool/MainTest.java | 115 ----- .../src/test/resources/application-test.yaml | 29 -- examples/webserver/tls/pom.xml | 91 ---- .../helidon/webserver/examples/tls/Main.java | 84 ---- .../webserver/examples/tls/package-info.java | 20 - .../tls/src/main/resources/application.yaml | 25 - .../tls/src/main/resources/certificate.p12 | Bin 2557 -> 0 bytes .../tls/src/main/resources/logging.properties | 20 - .../webserver/examples/tls/MainTest.java | 115 ----- .../src/test/resources/test-application.yaml | 22 - examples/webserver/tutorial/README.md | 10 - examples/webserver/tutorial/pom.xml | 83 ---- .../examples/tutorial/CommentService.java | 164 ------ .../webserver/examples/tutorial/Main.java | 84 ---- .../examples/tutorial/UpperXFilter.java | 66 --- .../examples/tutorial/package-info.java | 22 - .../examples/tutorial/user/User.java | 79 --- .../examples/tutorial/user/UserFilter.java | 41 -- .../examples/tutorial/user/package-info.java | 24 - .../examples/tutorial/CommentServiceTest.java | 91 ---- .../webserver/examples/tutorial/MainTest.java | 50 -- .../tutorial/user/UserFilterTest.java | 57 --- examples/webserver/websocket/README.md | 13 - examples/webserver/websocket/pom.xml | 95 ---- .../webserver/examples/websocket/Main.java | 79 --- .../websocket/MessageBoardEndpoint.java | 84 ---- .../examples/websocket/MessageQueue.java | 78 --- .../websocket/MessageQueueService.java | 44 -- .../examples/websocket/package-info.java | 25 - .../src/main/resources/WEB/index.html | 81 --- .../src/main/resources/logging.properties | 20 - .../examples/websocket/MessageBoardTest.java | 131 ----- pom.xml | 2 +- 1355 files changed, 52 insertions(+), 86067 deletions(-) create mode 100755 etc/scripts/build-examples.sh delete mode 100644 examples/config/README.md delete mode 100644 examples/config/basics/README.md delete mode 100644 examples/config/basics/pom.xml delete mode 100644 examples/config/basics/src/main/java/io/helidon/config/examples/basics/Main.java delete mode 100644 examples/config/basics/src/main/java/io/helidon/config/examples/basics/package-info.java delete mode 100644 examples/config/basics/src/main/resources/application.conf delete mode 100644 examples/config/basics/src/main/resources/logging.properties delete mode 100644 examples/config/changes/README.md delete mode 100644 examples/config/changes/conf/config.yaml delete mode 100644 examples/config/changes/conf/dev.yaml delete mode 100644 examples/config/changes/conf/secrets/password delete mode 100644 examples/config/changes/conf/secrets/username delete mode 100644 examples/config/changes/pom.xml delete mode 100644 examples/config/changes/src/main/java/io/helidon/config/examples/changes/AsSupplierExample.java delete mode 100644 examples/config/changes/src/main/java/io/helidon/config/examples/changes/Main.java delete mode 100644 examples/config/changes/src/main/java/io/helidon/config/examples/changes/OnChangeExample.java delete mode 100644 examples/config/changes/src/main/java/io/helidon/config/examples/changes/package-info.java delete mode 100644 examples/config/changes/src/main/resources/default.yaml delete mode 100644 examples/config/changes/src/main/resources/logging.properties delete mode 100644 examples/config/git/README.md delete mode 100644 examples/config/git/pom.xml delete mode 100644 examples/config/git/src/main/java/io/helidon/config/examples/git/Main.java delete mode 100644 examples/config/git/src/main/java/io/helidon/config/examples/git/package-info.java delete mode 100644 examples/config/git/src/main/resources/logging.properties delete mode 100644 examples/config/mapping/README.md delete mode 100644 examples/config/mapping/pom.xml delete mode 100644 examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/BuilderExample.java delete mode 100644 examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/DeserializationExample.java delete mode 100644 examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/FactoryMethodExample.java delete mode 100644 examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/Main.java delete mode 100644 examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/package-info.java delete mode 100644 examples/config/mapping/src/main/resources/application.conf delete mode 100644 examples/config/mapping/src/main/resources/logging.properties delete mode 100644 examples/config/metadata/README.md delete mode 100644 examples/config/metadata/pom.xml delete mode 100644 examples/config/metadata/src/main/java/io/helidon/config/examples/metadata/ConfigMetadataMain.java delete mode 100644 examples/config/metadata/src/main/java/io/helidon/config/examples/metadata/ConfiguredType.java delete mode 100644 examples/config/metadata/src/main/java/io/helidon/config/examples/metadata/package-info.java delete mode 100644 examples/config/overrides/README.md delete mode 100644 examples/config/overrides/conf/overrides.properties delete mode 100644 examples/config/overrides/conf/priority-config.yaml delete mode 100644 examples/config/overrides/pom.xml delete mode 100644 examples/config/overrides/src/main/java/io/helidon/config/examples/overrides/Main.java delete mode 100644 examples/config/overrides/src/main/java/io/helidon/config/examples/overrides/package-info.java delete mode 100644 examples/config/overrides/src/main/resources/application.yaml delete mode 100644 examples/config/overrides/src/main/resources/logging.properties delete mode 100644 examples/config/pom.xml delete mode 100644 examples/config/profiles/README.md delete mode 100644 examples/config/profiles/config-profile-prod.yaml delete mode 100644 examples/config/profiles/config/config-prod.yaml delete mode 100644 examples/config/profiles/pom.xml delete mode 100644 examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/Main.java delete mode 100644 examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/package-info.java delete mode 100644 examples/config/profiles/src/main/resources/application-local.yaml delete mode 100644 examples/config/profiles/src/main/resources/application-stage.yaml delete mode 100644 examples/config/profiles/src/main/resources/application.yaml delete mode 100644 examples/config/profiles/src/main/resources/config-profile-dev.yaml delete mode 100644 examples/config/profiles/src/main/resources/config-profile-stage.yaml delete mode 100644 examples/config/sources/README.md delete mode 100644 examples/config/sources/conf/config.yaml delete mode 100644 examples/config/sources/conf/dev.yaml delete mode 100644 examples/config/sources/conf/meta-config.yaml delete mode 100644 examples/config/sources/conf/secrets/password delete mode 100644 examples/config/sources/conf/secrets/username delete mode 100644 examples/config/sources/pom.xml delete mode 100644 examples/config/sources/src/main/java/io/helidon/config/examples/sources/DirectorySourceExample.java delete mode 100644 examples/config/sources/src/main/java/io/helidon/config/examples/sources/LoadSourcesExample.java delete mode 100644 examples/config/sources/src/main/java/io/helidon/config/examples/sources/Main.java delete mode 100644 examples/config/sources/src/main/java/io/helidon/config/examples/sources/WithSourcesExample.java delete mode 100644 examples/config/sources/src/main/java/io/helidon/config/examples/sources/package-info.java delete mode 100644 examples/config/sources/src/main/resources/default.yaml delete mode 100644 examples/config/sources/src/main/resources/logging.properties delete mode 100644 examples/config/sources/src/main/resources/meta-config.yaml delete mode 100644 examples/config/sources/src/main/resources/overrides.properties delete mode 100644 examples/cors/README.md delete mode 100644 examples/cors/pom.xml delete mode 100644 examples/cors/src/main/java/io/helidon/examples/cors/GreetService.java delete mode 100644 examples/cors/src/main/java/io/helidon/examples/cors/GreetingMessage.java delete mode 100644 examples/cors/src/main/java/io/helidon/examples/cors/Main.java delete mode 100644 examples/cors/src/main/java/io/helidon/examples/cors/package-info.java delete mode 100644 examples/cors/src/main/resources/META-INF/openapi.yml delete mode 100644 examples/cors/src/main/resources/application.yaml delete mode 100644 examples/cors/src/main/resources/logging.properties delete mode 100644 examples/cors/src/test/java/io/helidon/examples/cors/MainTest.java delete mode 100644 examples/dbclient/README.md delete mode 100644 examples/dbclient/common/pom.xml delete mode 100644 examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/AbstractPokemonService.java delete mode 100644 examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/Pokemon.java delete mode 100644 examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapper.java delete mode 100644 examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapperProvider.java delete mode 100644 examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/package-info.java delete mode 100644 examples/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider delete mode 100644 examples/dbclient/jdbc/README.md delete mode 100644 examples/dbclient/jdbc/pom.xml delete mode 100644 examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/JdbcExampleMain.java delete mode 100644 examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/PokemonService.java delete mode 100644 examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/package-info.java delete mode 100644 examples/dbclient/jdbc/src/main/resources/application.yaml delete mode 100644 examples/dbclient/jdbc/src/main/resources/logging.properties delete mode 100644 examples/dbclient/mongodb/README.md delete mode 100644 examples/dbclient/mongodb/pom.xml delete mode 100644 examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/MongoDbExampleMain.java delete mode 100644 examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/PokemonService.java delete mode 100644 examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/package-info.java delete mode 100644 examples/dbclient/mongodb/src/main/resources/application.yaml delete mode 100644 examples/dbclient/mongodb/src/main/resources/logging.properties delete mode 100644 examples/dbclient/pokemons/README.md delete mode 100644 examples/dbclient/pokemons/pom.xml delete mode 100644 examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/InitializeDb.java delete mode 100644 examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Pokemon.java delete mode 100644 examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMain.java delete mode 100644 examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapper.java delete mode 100644 examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapperProvider.java delete mode 100644 examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonService.java delete mode 100644 examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/package-info.java delete mode 100644 examples/dbclient/pokemons/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider delete mode 100644 examples/dbclient/pokemons/src/main/resources/Pokemons.json delete mode 100644 examples/dbclient/pokemons/src/main/resources/Types.json delete mode 100644 examples/dbclient/pokemons/src/main/resources/application.yaml delete mode 100644 examples/dbclient/pokemons/src/main/resources/logging.properties delete mode 100644 examples/dbclient/pokemons/src/main/resources/mongo.yaml delete mode 100644 examples/dbclient/pom.xml delete mode 100644 examples/employee-app/.dockerignore delete mode 100644 examples/employee-app/Dockerfile delete mode 100644 examples/employee-app/README.md delete mode 100644 examples/employee-app/app.yaml delete mode 100644 examples/employee-app/pom.xml delete mode 100644 examples/employee-app/src/main/java/io/helidon/service/employee/Employee.java delete mode 100644 examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepository.java delete mode 100644 examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImpl.java delete mode 100644 examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImplDB.java delete mode 100644 examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeService.java delete mode 100644 examples/employee-app/src/main/java/io/helidon/service/employee/Main.java delete mode 100644 examples/employee-app/src/main/java/io/helidon/service/employee/package-info.java delete mode 100644 examples/employee-app/src/main/resources/application.yaml delete mode 100644 examples/employee-app/src/main/resources/employees.json delete mode 100644 examples/employee-app/src/main/resources/logging.properties delete mode 100644 examples/employee-app/src/main/resources/public/EmployeeController.js delete mode 100644 examples/employee-app/src/main/resources/public/index.html delete mode 100644 examples/employee-app/src/main/resources/public/nopic.png delete mode 100644 examples/employee-app/src/test/java/io/helidon/service/employee/MainTest.java delete mode 100644 examples/graphql/basics/README.md delete mode 100644 examples/graphql/basics/pom.xml delete mode 100644 examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/Main.java delete mode 100644 examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/package-info.java delete mode 100644 examples/graphql/pom.xml delete mode 100644 examples/grpc/.dockerignore delete mode 100644 examples/grpc/README.md delete mode 100644 examples/grpc/basics/README.md delete mode 100644 examples/grpc/basics/pom.xml delete mode 100644 examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/HealthClient.java delete mode 100644 examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/Server.java delete mode 100644 examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/package-info.java delete mode 100644 examples/grpc/basics/src/main/resources/application.yaml delete mode 100644 examples/grpc/basics/src/main/resources/logging.properties delete mode 100644 examples/grpc/client-standalone/README.md delete mode 100644 examples/grpc/client-standalone/pom.xml delete mode 100644 examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/StandaloneClient.java delete mode 100644 examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/package-info.java delete mode 100644 examples/grpc/client-standalone/src/main/proto/strings.proto delete mode 100644 examples/grpc/client-standalone/src/main/resources/logging.properties delete mode 100644 examples/grpc/common/README.md delete mode 100644 examples/grpc/common/pom.xml delete mode 100644 examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/EchoService.java delete mode 100644 examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetClient.java delete mode 100644 examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetService.java delete mode 100644 examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetServiceJava.java delete mode 100644 examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringClient.java delete mode 100644 examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringService.java delete mode 100644 examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/package-info.java delete mode 100644 examples/grpc/common/src/main/proto/echo.proto delete mode 100644 examples/grpc/common/src/main/proto/greet.proto delete mode 100644 examples/grpc/common/src/main/proto/strings.proto delete mode 100644 examples/grpc/metrics/README.md delete mode 100644 examples/grpc/metrics/pom.xml delete mode 100644 examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/Server.java delete mode 100644 examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/package-info.java delete mode 100644 examples/grpc/metrics/src/main/resources/application.yaml delete mode 100644 examples/grpc/metrics/src/main/resources/logging.properties delete mode 100644 examples/grpc/microprofile/basic-client/README.md delete mode 100644 examples/grpc/microprofile/basic-client/pom.xml delete mode 100644 examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncClient.java delete mode 100644 examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncStringService.java delete mode 100644 examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/Client.java delete mode 100644 examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/StringService.java delete mode 100644 examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/package-info.java delete mode 100644 examples/grpc/microprofile/basic-client/src/main/resources/META-INF/beans.xml delete mode 100644 examples/grpc/microprofile/basic-client/src/main/resources/application.yaml delete mode 100644 examples/grpc/microprofile/basic-client/src/main/resources/logging.properties delete mode 100644 examples/grpc/microprofile/basic-server-implicit/README.md delete mode 100644 examples/grpc/microprofile/basic-server-implicit/pom.xml delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AdditionalServices.java delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AsyncStringService.java delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/StringService.java delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/package-info.java delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/beans.xml delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/services/io.helidon.microprofile.grpc.server.spi.GrpcMpExtension delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/resources/application.yaml delete mode 100644 examples/grpc/microprofile/basic-server-implicit/src/main/resources/logging.properties delete mode 100644 examples/grpc/microprofile/metrics/README.md delete mode 100644 examples/grpc/microprofile/metrics/pom.xml delete mode 100644 examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/StringService.java delete mode 100644 examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/package-info.java delete mode 100644 examples/grpc/microprofile/metrics/src/main/resources/META-INF/beans.xml delete mode 100644 examples/grpc/microprofile/metrics/src/main/resources/application.yaml delete mode 100644 examples/grpc/microprofile/metrics/src/main/resources/logging.properties delete mode 100644 examples/grpc/microprofile/pom.xml delete mode 100644 examples/grpc/opentracing/README.md delete mode 100644 examples/grpc/opentracing/pom.xml delete mode 100644 examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/ZipkinExampleMain.java delete mode 100644 examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/package-info.java delete mode 100644 examples/grpc/opentracing/src/main/resources/application.yaml delete mode 100644 examples/grpc/opentracing/src/main/resources/logging.properties delete mode 100644 examples/grpc/pom.xml delete mode 100644 examples/grpc/security-abac/README.md delete mode 100644 examples/grpc/security-abac/pom.xml delete mode 100644 examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServer.java delete mode 100644 examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServerFromConfig.java delete mode 100644 examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProvider.java delete mode 100644 examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProviderService.java delete mode 100644 examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/SecureStringClient.java delete mode 100644 examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/package-info.java delete mode 100644 examples/grpc/security-abac/src/main/resources/META-INF/native-image/helidon-examples/grpc-security-abac/reflect-config.json delete mode 100644 examples/grpc/security-abac/src/main/resources/META-INF/services/io.helidon.security.spi.SecurityProviderService delete mode 100644 examples/grpc/security-abac/src/main/resources/application.yaml delete mode 100644 examples/grpc/security-abac/src/main/resources/logging.properties delete mode 100644 examples/grpc/security-outbound/README.md delete mode 100644 examples/grpc/security-outbound/pom.xml delete mode 100644 examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureGreetClient.java delete mode 100644 examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureServer.java delete mode 100644 examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/package-info.java delete mode 100644 examples/grpc/security-outbound/src/main/resources/application.yaml delete mode 100644 examples/grpc/security-outbound/src/main/resources/logging.properties delete mode 100644 examples/grpc/security/README.md delete mode 100644 examples/grpc/security/pom.xml delete mode 100644 examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureGreetClient.java delete mode 100644 examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureServer.java delete mode 100644 examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureStringClient.java delete mode 100644 examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/package-info.java delete mode 100644 examples/grpc/security/src/main/resources/application.yaml delete mode 100644 examples/grpc/security/src/main/resources/logging.properties delete mode 100644 examples/health/basics/README.md delete mode 100644 examples/health/basics/pom.xml delete mode 100644 examples/health/basics/src/main/java/io/helidon/examples/health/basics/Main.java delete mode 100644 examples/health/basics/src/main/java/io/helidon/examples/health/basics/package-info.java delete mode 100644 examples/health/pom.xml delete mode 100644 examples/integrations/README.md delete mode 100644 examples/integrations/cdi/README.md delete mode 100644 examples/integrations/cdi/datasource-hikaricp-h2/README.md delete mode 100644 examples/integrations/cdi/datasource-hikaricp-h2/pom.xml delete mode 100644 examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java delete mode 100644 examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java delete mode 100644 examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/cdi/datasource-hikaricp-mysql/README.md delete mode 100644 examples/integrations/cdi/datasource-hikaricp-mysql/pom.xml delete mode 100644 examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java delete mode 100644 examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java delete mode 100644 examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/cdi/datasource-hikaricp/.dockerignore delete mode 100644 examples/integrations/cdi/datasource-hikaricp/Dockerfile delete mode 100644 examples/integrations/cdi/datasource-hikaricp/README.md delete mode 100644 examples/integrations/cdi/datasource-hikaricp/pom.xml delete mode 100644 examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java delete mode 100644 examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java delete mode 100644 examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/cdi/jedis/.dockerignore delete mode 100644 examples/integrations/cdi/jedis/Dockerfile delete mode 100644 examples/integrations/cdi/jedis/README.md delete mode 100644 examples/integrations/cdi/jedis/app.yaml delete mode 100644 examples/integrations/cdi/jedis/pom.xml delete mode 100644 examples/integrations/cdi/jedis/redis.yaml delete mode 100644 examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/RedisClientResource.java delete mode 100644 examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/package-info.java delete mode 100644 examples/integrations/cdi/jedis/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/cdi/jedis/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/cdi/jpa/README.md delete mode 100644 examples/integrations/cdi/jpa/pom.xml delete mode 100644 examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/Greeting.java delete mode 100644 examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldApplication.java delete mode 100644 examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldResource.java delete mode 100644 examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/JPAExceptionMapper.java delete mode 100644 examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/package-info.java delete mode 100644 examples/integrations/cdi/jpa/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/cdi/jpa/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/cdi/jpa/src/main/resources/META-INF/persistence.xml delete mode 100644 examples/integrations/cdi/pokemons/README.md delete mode 100644 examples/integrations/cdi/pokemons/pom.xml delete mode 100644 examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/Pokemon.java delete mode 100644 examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonResource.java delete mode 100644 examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonType.java delete mode 100644 examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonTypeResource.java delete mode 100644 examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/package-info.java delete mode 100644 examples/integrations/cdi/pokemons/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/cdi/pokemons/src/main/resources/META-INF/init_script.sql delete mode 100644 examples/integrations/cdi/pokemons/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/cdi/pokemons/src/main/resources/META-INF/persistence.xml delete mode 100644 examples/integrations/cdi/pokemons/src/test/java/io/helidon/examples/integrations/cdi/pokemon/MainTest.java delete mode 100644 examples/integrations/cdi/pom.xml delete mode 100644 examples/integrations/micrometer/mp/README.md delete mode 100644 examples/integrations/micrometer/mp/pom.xml delete mode 100644 examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetResource.java delete mode 100644 examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingMessage.java delete mode 100644 examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingProvider.java delete mode 100644 examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/package-info.java delete mode 100644 examples/integrations/micrometer/mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/micrometer/mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/micrometer/mp/src/main/resources/application.yaml delete mode 100644 examples/integrations/micrometer/mp/src/main/resources/logging.properties delete mode 100644 examples/integrations/micrometer/mp/src/test/java/io/helidon/examples/integrations/micrometer/mp/TestEndpoint.java delete mode 100644 examples/integrations/micrometer/pom.xml delete mode 100644 examples/integrations/micrometer/se/README.md delete mode 100644 examples/integrations/micrometer/se/pom.xml delete mode 100644 examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/GreetService.java delete mode 100644 examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/GreetingMessage.java delete mode 100644 examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/Main.java delete mode 100644 examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/package-info.java delete mode 100644 examples/integrations/micrometer/se/src/main/resources/application.yaml delete mode 100644 examples/integrations/micrometer/se/src/test/java/io/helidon/examples/micrometer/se/MainTest.java delete mode 100644 examples/integrations/micronaut/data/README.md delete mode 100644 examples/integrations/micronaut/data/pom.xml delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/BeanValidationExceptionMapper.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPetRepository.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/OwnerResource.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/PetResource.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/NameDTO.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Owner.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Pet.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/package-info.java delete mode 100644 examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/package-info.java delete mode 100644 examples/integrations/micronaut/data/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/micronaut/data/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/micronaut/data/src/main/resources/logging.properties delete mode 100644 examples/integrations/micronaut/data/src/test/java/io/helidon/examples/integrations/micronaut/data/MicronautExampleTest.java delete mode 100644 examples/integrations/micronaut/pom.xml delete mode 100644 examples/integrations/microstream/README.md delete mode 100644 examples/integrations/microstream/greetings-mp/README.md delete mode 100644 examples/integrations/microstream/greetings-mp/pom.xml delete mode 100644 examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetResource.java delete mode 100644 examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingMessage.java delete mode 100644 examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingProvider.java delete mode 100644 examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/package-info.java delete mode 100644 examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/microstream/greetings-mp/src/test/java/io/helidon/examples/integrations/microstream/greetings/mp/MicrostreamExampleGreetingsMpTest.java delete mode 100644 examples/integrations/microstream/greetings-se/README.md delete mode 100644 examples/integrations/microstream/greetings-se/pom.xml delete mode 100644 examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingService.java delete mode 100644 examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingServiceMicrostreamContext.java delete mode 100644 examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/LogEntry.java delete mode 100644 examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/Main.java delete mode 100644 examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamSingleThreadedExecutionContext.java delete mode 100644 examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/package-info.java delete mode 100644 examples/integrations/microstream/greetings-se/src/main/resources/application.yaml delete mode 100644 examples/integrations/microstream/greetings-se/src/test/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExampleGreetingsSeTest.java delete mode 100644 examples/integrations/microstream/pom.xml delete mode 100644 examples/integrations/neo4j/neo4j-mp/.dockerignore delete mode 100644 examples/integrations/neo4j/neo4j-mp/Dockerfile delete mode 100644 examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink delete mode 100644 examples/integrations/neo4j/neo4j-mp/Dockerfile.native delete mode 100644 examples/integrations/neo4j/neo4j-mp/README.md delete mode 100644 examples/integrations/neo4j/neo4j-mp/app.yaml delete mode 100644 examples/integrations/neo4j/neo4j-mp/pom.xml delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/Neo4jResource.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Actor.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Movie.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/MovieRepository.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Person.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/package-info.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/package-info.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/main/resources/logging.properties delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/MainTest.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/package-info.java delete mode 100644 examples/integrations/neo4j/neo4j-mp/src/test/resources/META-INF/microprofile-config.properties delete mode 100644 examples/integrations/neo4j/neo4j-se/.dockerignore delete mode 100644 examples/integrations/neo4j/neo4j-se/Dockerfile delete mode 100644 examples/integrations/neo4j/neo4j-se/Dockerfile.jlink delete mode 100644 examples/integrations/neo4j/neo4j-se/Dockerfile.native delete mode 100644 examples/integrations/neo4j/neo4j-se/README.md delete mode 100644 examples/integrations/neo4j/neo4j-se/app.yaml delete mode 100644 examples/integrations/neo4j/neo4j-se/pom.xml delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/Main.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/MovieService.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Actor.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Movie.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/MovieRepository.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Person.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/package-info.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/package-info.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/resources/application.yaml delete mode 100644 examples/integrations/neo4j/neo4j-se/src/main/resources/logging.properties delete mode 100644 examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java delete mode 100644 examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/package-info.java delete mode 100644 examples/integrations/neo4j/pom.xml delete mode 100644 examples/integrations/oci/README.md delete mode 100644 examples/integrations/oci/atp-cdi/README.md delete mode 100644 examples/integrations/oci/atp-cdi/pom.xml delete mode 100644 examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/AtpResource.java delete mode 100644 examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/package-info.java delete mode 100644 examples/integrations/oci/atp-cdi/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/oci/atp-cdi/src/main/resources/application.yaml delete mode 100644 examples/integrations/oci/atp-cdi/src/main/resources/logging.properties delete mode 100644 examples/integrations/oci/atp-reactive/README.md delete mode 100644 examples/integrations/oci/atp-reactive/pom.xml delete mode 100644 examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/AtpService.java delete mode 100644 examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciAtpMain.java delete mode 100644 examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciResponseHandler.java delete mode 100644 examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/package-info.java delete mode 100644 examples/integrations/oci/atp-reactive/src/main/resources/application.yaml delete mode 100644 examples/integrations/oci/atp-reactive/src/main/resources/logging.properties delete mode 100644 examples/integrations/oci/metrics-reactive/pom.xml delete mode 100644 examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/OciMetricsMain.java delete mode 100644 examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/package-info.java delete mode 100644 examples/integrations/oci/metrics-reactive/src/main/resources/application.yaml delete mode 100644 examples/integrations/oci/metrics-reactive/src/main/resources/logging.properties delete mode 100644 examples/integrations/oci/objectstorage-cdi/pom.xml delete mode 100644 examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageCdiMain.java delete mode 100644 examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageResource.java delete mode 100644 examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/package-info.java delete mode 100644 examples/integrations/oci/objectstorage-cdi/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/oci/objectstorage-cdi/src/main/resources/application.yaml delete mode 100644 examples/integrations/oci/objectstorage-cdi/src/main/resources/logging.properties delete mode 100644 examples/integrations/oci/objectstorage-reactive/pom.xml delete mode 100644 examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/ObjectStorageService.java delete mode 100644 examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/OciObjectStorageMain.java delete mode 100644 examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/package-info.java delete mode 100644 examples/integrations/oci/objectstorage-reactive/src/main/resources/application.yaml delete mode 100644 examples/integrations/oci/objectstorage-reactive/src/main/resources/logging.properties delete mode 100644 examples/integrations/oci/pom.xml delete mode 100644 examples/integrations/oci/vault-cdi/pom.xml delete mode 100644 examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/CryptoClientProducer.java delete mode 100644 examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/ErrorHandlerProvider.java delete mode 100644 examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultCdiMain.java delete mode 100644 examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultResource.java delete mode 100644 examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/package-info.java delete mode 100644 examples/integrations/oci/vault-cdi/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/oci/vault-cdi/src/main/resources/application.yaml delete mode 100644 examples/integrations/oci/vault-cdi/src/main/resources/logging.properties delete mode 100644 examples/integrations/oci/vault-reactive/pom.xml delete mode 100644 examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciHandler.java delete mode 100644 examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciVaultMain.java delete mode 100644 examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/VaultService.java delete mode 100644 examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/package-info.java delete mode 100644 examples/integrations/oci/vault-reactive/src/main/resources/application.yaml delete mode 100644 examples/integrations/oci/vault-reactive/src/main/resources/logging.properties delete mode 100644 examples/integrations/pom.xml delete mode 100644 examples/integrations/vault/hcp-cdi/README.md delete mode 100644 examples/integrations/vault/hcp-cdi/pom.xml delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/CubbyholeResource.java delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv1Resource.java delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv2Resource.java delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/TransitResource.java delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/VaultCdiMain.java delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/package-info.java delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/resources/META-INF/beans.xml delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/resources/application.yaml delete mode 100644 examples/integrations/vault/hcp-cdi/src/main/resources/logging.properties delete mode 100644 examples/integrations/vault/hcp-reactive/README.md delete mode 100644 examples/integrations/vault/hcp-reactive/pom.xml delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/AppRoleExample.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/CubbyholeService.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/K8sExample.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv1Service.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv2Service.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/ReactiveVaultMain.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/TransitService.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/VaultPolicy.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/package-info.java delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/resources/application.yaml delete mode 100644 examples/integrations/vault/hcp-reactive/src/main/resources/logging.properties delete mode 100644 examples/integrations/vault/pom.xml delete mode 100644 examples/jbatch/README.md delete mode 100644 examples/jbatch/pom.xml delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/BatchResource.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/HelidonExecutorServiceProvider.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyBatchlet.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyInputRecord.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemProcessor.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemReader.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemWriter.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyOutputRecord.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/package-info.java delete mode 100644 examples/jbatch/src/main/java/io/helidon/jbatch/example/package-info.java delete mode 100644 examples/jbatch/src/main/resources/META-INF/batch-jobs/myJob.xml delete mode 100644 examples/jbatch/src/main/resources/META-INF/beans.xml delete mode 100644 examples/jbatch/src/main/resources/META-INF/helidon/serial-config.properties delete mode 100644 examples/jbatch/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/jbatch/src/main/resources/logging.properties delete mode 100644 examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java delete mode 100644 examples/k8s/zipkin.yaml delete mode 100644 examples/logging/jul/README.md delete mode 100644 examples/logging/jul/pom.xml delete mode 100644 examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/Main.java delete mode 100644 examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/package-info.java delete mode 100644 examples/logging/jul/src/main/resources/logging.properties delete mode 100644 examples/logging/log4j/README.md delete mode 100644 examples/logging/log4j/pom.xml delete mode 100644 examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/Main.java delete mode 100644 examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/package-info.java delete mode 100644 examples/logging/logback-aot/README.md delete mode 100644 examples/logging/logback-aot/logback-runtime.xml delete mode 100644 examples/logging/logback-aot/pom.xml delete mode 100644 examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/Main.java delete mode 100644 examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/package-info.java delete mode 100644 examples/logging/logback-aot/src/main/resources/logback.xml delete mode 100644 examples/logging/pom.xml delete mode 100644 examples/logging/slf4j/README.md delete mode 100644 examples/logging/slf4j/pom.xml delete mode 100644 examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/Main.java delete mode 100644 examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/package-info.java delete mode 100644 examples/logging/slf4j/src/main/resources/logback.xml delete mode 100644 examples/media/multipart/README.md delete mode 100644 examples/media/multipart/pom.xml delete mode 100644 examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java delete mode 100644 examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileStorage.java delete mode 100644 examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/Main.java delete mode 100644 examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/package-info.java delete mode 100644 examples/media/multipart/src/main/resources/WEB/index.html delete mode 100644 examples/media/multipart/src/test/java/io/helidon/examples/media/multipart/FileServiceTest.java delete mode 100644 examples/media/pom.xml delete mode 100644 examples/messaging/README.md delete mode 100644 examples/messaging/docker/kafka/Dockerfile.kafka delete mode 100644 examples/messaging/docker/kafka/init_topics.sh delete mode 100644 examples/messaging/docker/kafka/start_kafka.sh delete mode 100644 examples/messaging/docker/oracle-aq-18-xe/Dockerfile delete mode 100644 examples/messaging/docker/oracle-aq-18-xe/buildAndRun.sh delete mode 100644 examples/messaging/docker/oracle-aq-18-xe/examples.sql delete mode 100644 examples/messaging/docker/oracle-aq-18-xe/init.sql delete mode 100644 examples/messaging/docker/oracle-aq-18-xe/stopAndClean.sh delete mode 100644 examples/messaging/jms-websocket-mp/README.md delete mode 100644 examples/messaging/jms-websocket-mp/pom.xml delete mode 100644 examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java delete mode 100644 examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java delete mode 100644 examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java delete mode 100644 examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/WEB/favicon.ico delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/arrow-1.png delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/arrow-2.png delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/cloud.png delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/frank.png delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/WEB/index.html delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/WEB/main.css delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/application.yaml delete mode 100644 examples/messaging/jms-websocket-mp/src/main/resources/logging.properties delete mode 100644 examples/messaging/jms-websocket-se/README.md delete mode 100644 examples/messaging/jms-websocket-se/pom.xml delete mode 100644 examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java delete mode 100644 examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java delete mode 100644 examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java delete mode 100644 examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/WEB/favicon.ico delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/WEB/img/arrow-1.png delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/WEB/img/arrow-2.png delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/WEB/img/cloud.png delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/WEB/img/frank.png delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/WEB/index.html delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/WEB/main.css delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/application.yaml delete mode 100644 examples/messaging/jms-websocket-se/src/main/resources/logging.properties delete mode 100644 examples/messaging/kafka-websocket-mp/README.md delete mode 100644 examples/messaging/kafka-websocket-mp/pom.xml delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/WEB/favicon.ico delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/arrow-1.png delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/arrow-2.png delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/cloud.png delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/frank.png delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/WEB/index.html delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/WEB/main.css delete mode 100644 examples/messaging/kafka-websocket-mp/src/main/resources/logging.properties delete mode 100644 examples/messaging/kafka-websocket-se/README.md delete mode 100644 examples/messaging/kafka-websocket-se/pom.xml delete mode 100644 examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java delete mode 100644 examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java delete mode 100644 examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java delete mode 100644 examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/WEB/favicon.ico delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/arrow-1.png delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/arrow-2.png delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/cloud.png delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/frank.png delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/WEB/index.html delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/WEB/main.css delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/application.yaml delete mode 100644 examples/messaging/kafka-websocket-se/src/main/resources/logging.properties delete mode 100755 examples/messaging/kafkaConsume.sh delete mode 100755 examples/messaging/kafkaProduce.sh delete mode 100755 examples/messaging/kafkaRun.sh delete mode 100644 examples/messaging/oracle-aq-websocket-mp/README.md delete mode 100644 examples/messaging/oracle-aq-websocket-mp/pom.xml delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/favicon.ico delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/arrow-1.png delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/arrow-2.png delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/cloud.png delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/frank.png delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/index.html delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/main.css delete mode 100644 examples/messaging/oracle-aq-websocket-mp/src/main/resources/logging.properties delete mode 100644 examples/messaging/pom.xml delete mode 100644 examples/messaging/weblogic-jms-mp/README.md delete mode 100644 examples/messaging/weblogic-jms-mp/buildAndRunWeblogic.sh delete mode 100644 examples/messaging/weblogic-jms-mp/extractThinClientLib.sh delete mode 100644 examples/messaging/weblogic-jms-mp/pom.xml delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/FrankResource.java delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/WEB/favicon.ico delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/arrow-1.png delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/arrow-2.png delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/cloud.png delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/frank.png delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/WEB/index.html delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/WEB/main.css delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/application.yaml delete mode 100644 examples/messaging/weblogic-jms-mp/src/main/resources/logging.properties delete mode 100644 examples/messaging/weblogic-jms-mp/weblogic/Dockerfile delete mode 100644 examples/messaging/weblogic-jms-mp/weblogic/container-scripts/create-wls-domain.py delete mode 100644 examples/messaging/weblogic-jms-mp/weblogic/container-scripts/createAndStartEmptyDomain.sh delete mode 100644 examples/messaging/weblogic-jms-mp/weblogic/container-scripts/get_healthcheck_url.sh delete mode 100644 examples/messaging/weblogic-jms-mp/weblogic/container-scripts/setupTestJMSQueue.py delete mode 100644 examples/messaging/weblogic-jms-mp/weblogic/properties/domain.properties delete mode 100644 examples/messaging/weblogic-jms-mp/weblogic/properties/domain_security.properties delete mode 100644 examples/metrics/exemplar/README.md delete mode 100644 examples/metrics/exemplar/pom.xml delete mode 100644 examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/GreetService.java delete mode 100644 examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/Main.java delete mode 100644 examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/package-info.java delete mode 100644 examples/metrics/exemplar/src/main/resources/application.yaml delete mode 100644 examples/metrics/exemplar/src/main/resources/logging.properties delete mode 100644 examples/metrics/exemplar/src/test/java/io/helidon/examples/metrics/exemplar/MainTest.java delete mode 100644 examples/metrics/exemplar/src/test/resources/test-app.yaml delete mode 100644 examples/metrics/filtering/mp/pom.xml delete mode 100644 examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetResource.java delete mode 100644 examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingMessage.java delete mode 100644 examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingProvider.java delete mode 100644 examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/package-info.java delete mode 100644 examples/metrics/filtering/mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/metrics/filtering/mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/metrics/filtering/mp/src/main/resources/logging.properties delete mode 100644 examples/metrics/filtering/mp/src/test/java/io/helidon/examples/metrics/filtering/mp/MainTest.java delete mode 100644 examples/metrics/filtering/pom.xml delete mode 100644 examples/metrics/filtering/se/pom.xml delete mode 100644 examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/GreetService.java delete mode 100644 examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/Main.java delete mode 100644 examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/package-info.java delete mode 100644 examples/metrics/filtering/se/src/main/resources/application.yaml delete mode 100644 examples/metrics/filtering/se/src/main/resources/logging.properties delete mode 100644 examples/metrics/filtering/se/src/test/java/io/helidon/examples/metrics/filtering/se/MainTest.java delete mode 100644 examples/metrics/http-status-count-se/README.md delete mode 100644 examples/metrics/http-status-count-se/pom.xml delete mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java delete mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java delete mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java delete mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java delete mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java delete mode 100644 examples/metrics/http-status-count-se/src/main/resources/application.yaml delete mode 100644 examples/metrics/http-status-count-se/src/main/resources/logging.properties delete mode 100644 examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java delete mode 100644 examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java delete mode 100644 examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java delete mode 100644 examples/metrics/http-status-count-se/src/test/resources/application.yaml delete mode 100644 examples/metrics/kpi/README.md delete mode 100644 examples/metrics/kpi/pom.xml delete mode 100644 examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/GreetService.java delete mode 100644 examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/Main.java delete mode 100644 examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/package-info.java delete mode 100644 examples/metrics/kpi/src/main/resources/application.yaml delete mode 100644 examples/metrics/kpi/src/main/resources/logging.properties delete mode 100644 examples/metrics/kpi/src/test/java/io/helidon/examples/metrics/kpi/MainTest.java delete mode 100644 examples/metrics/pom.xml delete mode 100644 examples/microprofile/README.md delete mode 100644 examples/microprofile/bean-validation/README.md delete mode 100644 examples/microprofile/bean-validation/pom.xml delete mode 100644 examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/ValidEmailResource.java delete mode 100644 examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/package-info.java delete mode 100644 examples/microprofile/bean-validation/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/bean-validation/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/bean-validation/src/main/resources/logging.properties delete mode 100644 examples/microprofile/bean-validation/src/test/java/io/helidon/tests/integration/bean/validation/TestValidationEndpoint.java delete mode 100644 examples/microprofile/cors/README.md delete mode 100644 examples/microprofile/cors/pom.xml delete mode 100644 examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetResource.java delete mode 100644 examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingMessage.java delete mode 100644 examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingProvider.java delete mode 100644 examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/package-info.java delete mode 100644 examples/microprofile/cors/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/cors/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/cors/src/main/resources/logging.properties delete mode 100644 examples/microprofile/cors/src/test/java/io/helidon/microprofile/examples/cors/TestCORS.java delete mode 100644 examples/microprofile/cors/src/test/resources/logging.properties delete mode 100644 examples/microprofile/graphql/README.md delete mode 100644 examples/microprofile/graphql/pom.xml delete mode 100644 examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/Task.java delete mode 100644 examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskApi.java delete mode 100644 examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskNotFoundException.java delete mode 100644 examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/package-info.java delete mode 100644 examples/microprofile/graphql/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/graphql/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/graphql/src/main/resources/logging.properties delete mode 100644 examples/microprofile/graphql/src/main/resources/web/index.html delete mode 100644 examples/microprofile/hello-world-explicit/README.md delete mode 100644 examples/microprofile/hello-world-explicit/pom.xml delete mode 100644 examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/HelloWorldResource.java delete mode 100644 examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/Main.java delete mode 100644 examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/package-info.java delete mode 100644 examples/microprofile/hello-world-explicit/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/hello-world-explicit/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/hello-world-explicit/src/main/resources/logging.properties delete mode 100644 examples/microprofile/hello-world-implicit/README.md delete mode 100644 examples/microprofile/hello-world-implicit/pom.xml delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java delete mode 100644 examples/microprofile/hello-world-implicit/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/hello-world-implicit/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/hello-world-implicit/src/main/resources/logging.properties delete mode 100644 examples/microprofile/hello-world-implicit/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java delete mode 100644 examples/microprofile/http-status-count-mp/README.md delete mode 100644 examples/microprofile/http-status-count-mp/app.yaml delete mode 100644 examples/microprofile/http-status-count-mp/pom.xml delete mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java delete mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingMessage.java delete mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java delete mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java delete mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java delete mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java delete mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json delete mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/application.yaml delete mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/logging.properties delete mode 100644 examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java delete mode 100644 examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java delete mode 100644 examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java delete mode 100644 examples/microprofile/http-status-count-mp/src/test/resources/application.yaml delete mode 100644 examples/microprofile/idcs/README.md delete mode 100644 examples/microprofile/idcs/pom.xml delete mode 100644 examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsApplication.java delete mode 100644 examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsMain.java delete mode 100644 examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsResource.java delete mode 100644 examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/ReactiveService.java delete mode 100644 examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/package-info.java delete mode 100644 examples/microprofile/idcs/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/idcs/src/main/resources/WEB/resource.html delete mode 100644 examples/microprofile/idcs/src/main/resources/application.yaml delete mode 100644 examples/microprofile/idcs/src/main/resources/logging.properties delete mode 100644 examples/microprofile/lra/README.md delete mode 100644 examples/microprofile/lra/pom.xml delete mode 100644 examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/LRAExampleResource.java delete mode 100644 examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/package-info.java delete mode 100644 examples/microprofile/lra/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/lra/src/main/resources/application.yaml delete mode 100644 examples/microprofile/lra/src/main/resources/logging.properties delete mode 100644 examples/microprofile/messaging-sse/README.md delete mode 100644 examples/microprofile/messaging-sse/pom.xml delete mode 100644 examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MessagingExampleResource.java delete mode 100644 examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MsgProcessingBean.java delete mode 100644 examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/package-info.java delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/WEB/favicon.ico delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/WEB/img/arrow-1.png delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/WEB/img/arrow-2.png delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/WEB/img/cloud.png delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/WEB/img/frank.png delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/WEB/index.html delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/WEB/main.css delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/application.yaml delete mode 100644 examples/microprofile/messaging-sse/src/main/resources/logging.properties delete mode 100644 examples/microprofile/multipart/README.md delete mode 100644 examples/microprofile/multipart/pom.xml delete mode 100644 examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileService.java delete mode 100644 examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileStorage.java delete mode 100644 examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/MultiPartFeatureProvider.java delete mode 100644 examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/package-info.java delete mode 100644 examples/microprofile/multipart/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/multipart/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/multipart/src/main/resources/WEB/index.html delete mode 100644 examples/microprofile/multipart/src/main/resources/logging.properties delete mode 100644 examples/microprofile/multipart/src/test/java/io/helidon/examples/microprofile/multipart/FileServiceTest.java delete mode 100644 examples/microprofile/multiport/README.md delete mode 100644 examples/microprofile/multiport/pom.xml delete mode 100644 examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateApplication.java delete mode 100644 examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateResource.java delete mode 100644 examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicApplication.java delete mode 100644 examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicResource.java delete mode 100644 examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/package-info.java delete mode 100644 examples/microprofile/multiport/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/multiport/src/main/resources/application.yaml delete mode 100644 examples/microprofile/multiport/src/test/java/io/helidon/examples/microprofile/multiport/MainTest.java delete mode 100644 examples/microprofile/oidc/README.md delete mode 100644 examples/microprofile/oidc/pom.xml delete mode 100644 examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcMain.java delete mode 100644 examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcResource.java delete mode 100644 examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/package-info.java delete mode 100644 examples/microprofile/oidc/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/oidc/src/main/resources/application.yaml delete mode 100644 examples/microprofile/oidc/src/main/resources/logging.properties delete mode 100644 examples/microprofile/openapi-basic/README.md delete mode 100644 examples/microprofile/openapi-basic/pom.xml delete mode 100644 examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetResource.java delete mode 100644 examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingMessage.java delete mode 100644 examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingProvider.java delete mode 100644 examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIFilter.java delete mode 100644 examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIModelReader.java delete mode 100644 examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/package-info.java delete mode 100644 examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/package-info.java delete mode 100644 examples/microprofile/openapi-basic/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/openapi-basic/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/openapi-basic/src/main/resources/logging.properties delete mode 100644 examples/microprofile/openapi-basic/src/test/java/io/helidon/microprofile/examples/openapi/basic/MainTest.java delete mode 100644 examples/microprofile/openapi-basic/src/test/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/pom.xml delete mode 100644 examples/microprofile/security/README.md delete mode 100644 examples/microprofile/security/pom.xml delete mode 100644 examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/HelloWorldResource.java delete mode 100644 examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/Main.java delete mode 100644 examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/OtherApp.java delete mode 100644 examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/StaticContentApp.java delete mode 100644 examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/package-info.java delete mode 100644 examples/microprofile/security/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/security/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/security/src/main/resources/WEB/resource.html delete mode 100644 examples/microprofile/security/src/main/resources/application.yaml delete mode 100644 examples/microprofile/security/src/main/resources/logging.properties delete mode 100644 examples/microprofile/static-content/README.md delete mode 100644 examples/microprofile/static-content/pom.xml delete mode 100644 examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/HelloWorldResource.java delete mode 100644 examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/Main.java delete mode 100644 examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/package-info.java delete mode 100644 examples/microprofile/static-content/src/main/java/module-info.java.txt delete mode 100644 examples/microprofile/static-content/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/static-content/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/static-content/src/main/resources/WEB/resource.html delete mode 100644 examples/microprofile/static-content/src/main/resources/logging.properties delete mode 100644 examples/microprofile/static-content/src/test/java/io/helidon/microprofile/example/staticc/StaticContentTest.java delete mode 100644 examples/microprofile/static-content/src/test/resources/logging.properties delete mode 100644 examples/microprofile/tls/README.md delete mode 100644 examples/microprofile/tls/pom.xml delete mode 100644 examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/GreetResource.java delete mode 100644 examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/Main.java delete mode 100644 examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/package-info.java delete mode 100644 examples/microprofile/tls/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/tls/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/tls/src/main/resources/logging.properties delete mode 100644 examples/microprofile/tls/src/main/resources/server.p12 delete mode 100644 examples/microprofile/tls/src/test/java/io/helidon/microprofile/example/tls/TlsTest.java delete mode 100644 examples/microprofile/tls/src/test/resources/META-INF/microprofile-config.properties delete mode 100644 examples/microprofile/websocket/README.md delete mode 100644 examples/microprofile/websocket/pom.xml delete mode 100644 examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageBoardEndpoint.java delete mode 100644 examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueue.java delete mode 100644 examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueueResource.java delete mode 100644 examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/package-info.java delete mode 100644 examples/microprofile/websocket/src/main/resources/META-INF/beans.xml delete mode 100644 examples/microprofile/websocket/src/main/resources/WEB/index.html delete mode 100644 examples/microprofile/websocket/src/main/resources/application.yaml delete mode 100644 examples/microprofile/websocket/src/main/resources/logging.properties delete mode 100644 examples/microprofile/websocket/src/test/java/io/helidon/microprofile/example/websocket/MessageBoardTest.java delete mode 100644 examples/openapi-tools/README.md delete mode 100644 examples/openapi-tools/pom.xml delete mode 100644 examples/openapi-tools/quickstart-mp/README.md delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/README.md delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/docs/Message.md delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/docs/MessageApi.md delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/pom.xml delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/JavaTimeFormatter.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiException.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiExceptionMapper.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageApi.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageService.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/package-info.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/Message.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/package-info.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/package-info.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/beans.xml delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/api/MessageApiTest.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/model/MessageTest.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/README.md delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/pom.xml delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/JavaTimeFormatter.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RestApplication.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageService.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/package-info.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/Message.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/package-info.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/package-info.java delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/beans.xml delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/openapi.yml delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/logging.properties delete mode 100644 examples/openapi-tools/quickstart-mp/mp-server/src/test/java/org/openapitools/server/model/MessageTest.java delete mode 100644 examples/openapi-tools/quickstart-mp/pom.xml delete mode 100644 examples/openapi-tools/quickstart-se/README.md delete mode 100644 examples/openapi-tools/quickstart-se/pom.xml delete mode 100644 examples/openapi-tools/quickstart-se/se-client/README.md delete mode 100644 examples/openapi-tools/quickstart-se/se-client/docs/Message.md delete mode 100644 examples/openapi-tools/quickstart-se/se-client/docs/MessageApi.md delete mode 100644 examples/openapi-tools/quickstart-se/se-client/pom.xml delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiClient.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponse.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponseBase.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Main.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Pair.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApi.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApiImpl.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageService.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/ResponseType.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/package-info.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/Message.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/package-info.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/package-info.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/main/resources/application.yaml delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/api/MessageApiTest.java delete mode 100644 examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/model/MessageTest.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/README.md delete mode 100644 examples/openapi-tools/quickstart-se/se-server/pom.xml delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/Main.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/JsonProvider.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageService.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/ValidatorUtils.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/package-info.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/Message.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/package-info.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/package-info.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/resources/META-INF/openapi.yml delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/resources/application.yaml delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/main/resources/logging.properties delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/MainTest.java delete mode 100644 examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/model/MessageTest.java delete mode 100644 examples/openapi-tools/quickstart.yaml delete mode 100644 examples/openapi/README.md delete mode 100644 examples/openapi/pom.xml delete mode 100644 examples/openapi/src/main/java/io/helidon/examples/openapi/GreetService.java delete mode 100644 examples/openapi/src/main/java/io/helidon/examples/openapi/GreetingMessage.java delete mode 100644 examples/openapi/src/main/java/io/helidon/examples/openapi/Main.java delete mode 100644 examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIFilter.java delete mode 100644 examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIModelReader.java delete mode 100644 examples/openapi/src/main/java/io/helidon/examples/openapi/internal/package-info.java delete mode 100644 examples/openapi/src/main/java/io/helidon/examples/openapi/package-info.java delete mode 100644 examples/openapi/src/main/resources/META-INF/openapi.yml delete mode 100644 examples/openapi/src/main/resources/application.yaml delete mode 100644 examples/openapi/src/main/resources/logging.properties delete mode 100644 examples/openapi/src/test/java/io/helidon/examples/openapi/MainTest.java delete mode 100644 examples/pom.xml delete mode 100644 examples/quickstarts/README.md delete mode 100644 examples/quickstarts/helidon-quickstart-mp/.dockerignore delete mode 100644 examples/quickstarts/helidon-quickstart-mp/.gitignore delete mode 100644 examples/quickstarts/helidon-quickstart-mp/Dockerfile delete mode 100644 examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink delete mode 100644 examples/quickstarts/helidon-quickstart-mp/Dockerfile.native delete mode 100644 examples/quickstarts/helidon-quickstart-mp/README.md delete mode 100644 examples/quickstarts/helidon-quickstart-mp/app.yaml delete mode 100644 examples/quickstarts/helidon-quickstart-mp/build.gradle delete mode 100644 examples/quickstarts/helidon-quickstart-mp/pom.xml delete mode 100644 examples/quickstarts/helidon-quickstart-mp/settings.gradle delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/main/resources/logging.properties delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java delete mode 100644 examples/quickstarts/helidon-quickstart-mp/src/test/resources/META-INF/microprofile-config.properties delete mode 100644 examples/quickstarts/helidon-quickstart-se/.dockerignore delete mode 100644 examples/quickstarts/helidon-quickstart-se/.gitignore delete mode 100644 examples/quickstarts/helidon-quickstart-se/Dockerfile delete mode 100644 examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink delete mode 100644 examples/quickstarts/helidon-quickstart-se/Dockerfile.native delete mode 100644 examples/quickstarts/helidon-quickstart-se/README.md delete mode 100644 examples/quickstarts/helidon-quickstart-se/app.yaml delete mode 100644 examples/quickstarts/helidon-quickstart-se/build.gradle delete mode 100644 examples/quickstarts/helidon-quickstart-se/pom.xml delete mode 100644 examples/quickstarts/helidon-quickstart-se/settings.gradle delete mode 100644 examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java delete mode 100644 examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java delete mode 100644 examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java delete mode 100644 examples/quickstarts/helidon-quickstart-se/src/main/resources/application.yaml delete mode 100644 examples/quickstarts/helidon-quickstart-se/src/main/resources/logging.properties delete mode 100644 examples/quickstarts/helidon-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java delete mode 100644 examples/quickstarts/helidon-quickstart-se/src/test/resources/config-profile.yaml delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/.dockerignore delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/.gitignore delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/README.md delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/app.yaml delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/beans.xml delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/logging.properties delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/.dockerignore delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/.gitignore delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/README.md delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/app.yaml delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/pom.xml delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/helidon-example-reflection-config.json delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/native-image.properties delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/application.yaml delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/logging.properties delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java delete mode 100644 examples/quickstarts/helidon-standalone-quickstart-se/src/test/resources/config-profile.yaml delete mode 100644 examples/quickstarts/pom.xml delete mode 100644 examples/security/README.md delete mode 100644 examples/security/attribute-based-access-control/README.md delete mode 100644 examples/security/attribute-based-access-control/pom.xml delete mode 100644 examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacApplication.java delete mode 100644 examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacExplicitResource.java delete mode 100644 examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacJerseyMain.java delete mode 100644 examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacResource.java delete mode 100644 examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AtnProvider.java delete mode 100644 examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/package-info.java delete mode 100644 examples/security/attribute-based-access-control/src/main/resources/META-INF/beans.xml delete mode 100644 examples/security/attribute-based-access-control/src/main/resources/application.yaml delete mode 100644 examples/security/attribute-based-access-control/src/main/resources/logging.properties delete mode 100644 examples/security/basic-auth-with-static-content/README.md delete mode 100644 examples/security/basic-auth-with-static-content/pom.xml delete mode 100644 examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderMain.java delete mode 100644 examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigMain.java delete mode 100644 examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleUtil.java delete mode 100644 examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/package-info.java delete mode 100644 examples/security/basic-auth-with-static-content/src/main/resources/WEB/index.html delete mode 100644 examples/security/basic-auth-with-static-content/src/main/resources/application.yaml delete mode 100644 examples/security/basic-auth-with-static-content/src/main/resources/logging.properties delete mode 100644 examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderTest.java delete mode 100644 examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigTest.java delete mode 100644 examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleTest.java delete mode 100644 examples/security/google-login/README.md delete mode 100644 examples/security/google-login/pom.xml delete mode 100644 examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleBuilderMain.java delete mode 100644 examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleConfigMain.java delete mode 100644 examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleUtil.java delete mode 100644 examples/security/google-login/src/main/java/io/helidon/security/examples/google/package-info.java delete mode 100644 examples/security/google-login/src/main/resources/WEB/index.html delete mode 100644 examples/security/google-login/src/main/resources/WEB/static/js/google-app.js delete mode 100644 examples/security/google-login/src/main/resources/application.yaml delete mode 100644 examples/security/google-login/src/main/resources/logging.properties delete mode 100644 examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleBuilderMainTest.java delete mode 100644 examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleConfigMainTest.java delete mode 100644 examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleMainTest.java delete mode 100644 examples/security/idcs-login/README.md delete mode 100644 examples/security/idcs-login/pom.xml delete mode 100644 examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsBuilderMain.java delete mode 100644 examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsMain.java delete mode 100644 examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsUtil.java delete mode 100644 examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/package-info.java delete mode 100644 examples/security/idcs-login/src/main/resources/application.yaml delete mode 100644 examples/security/idcs-login/src/main/resources/logging.properties delete mode 100644 examples/security/jersey/README.md delete mode 100644 examples/security/jersey/pom.xml delete mode 100644 examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyBuilderMain.java delete mode 100644 examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyConfigMain.java delete mode 100644 examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyProgrammaticMain.java delete mode 100644 examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyResources.java delete mode 100644 examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyUtil.java delete mode 100644 examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/package-info.java delete mode 100644 examples/security/jersey/src/main/resources/application.yaml delete mode 100644 examples/security/jersey/src/main/resources/logging.properties delete mode 100644 examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyBuilderMainTest.java delete mode 100644 examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyConfigMainTest.java delete mode 100644 examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyMainTest.java delete mode 100644 examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyProgrammaticMainTest.java delete mode 100644 examples/security/nohttp-programmatic/README.md delete mode 100644 examples/security/nohttp-programmatic/pom.xml delete mode 100644 examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/MyProvider.java delete mode 100644 examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/ProgrammaticSecurity.java delete mode 100644 examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/package-info.java delete mode 100644 examples/security/nohttp-programmatic/src/main/resources/logging.properties delete mode 100644 examples/security/outbound-override/README.md delete mode 100644 examples/security/outbound-override/pom.xml delete mode 100644 examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideExample.java delete mode 100644 examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExample.java delete mode 100644 examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideUtil.java delete mode 100644 examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/package-info.java delete mode 100644 examples/security/outbound-override/src/main/resources/client-service-jwt.yaml delete mode 100644 examples/security/outbound-override/src/main/resources/client-service.yaml delete mode 100644 examples/security/outbound-override/src/main/resources/serving-service-jwt.yaml delete mode 100644 examples/security/outbound-override/src/main/resources/serving-service.yaml delete mode 100644 examples/security/outbound-override/src/main/resources/signing-jwk.json delete mode 100644 examples/security/outbound-override/src/main/resources/verifying-jwk.json delete mode 100644 examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideExampleTest.java delete mode 100644 examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExampleTest.java delete mode 100644 examples/security/pom.xml delete mode 100644 examples/security/spi-examples/README.md delete mode 100644 examples/security/spi-examples/pom.xml delete mode 100644 examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtnProviderSync.java delete mode 100644 examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtzProviderSync.java delete mode 100644 examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/Auditer.java delete mode 100644 examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/OutboundProviderSync.java delete mode 100644 examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/ProviderSelector.java delete mode 100644 examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/package-info.java delete mode 100644 examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtnProviderSyncTest.java delete mode 100644 examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtzProviderSyncTest.java delete mode 100644 examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AuditerTest.java delete mode 100644 examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/OutboundProviderSyncTest.java delete mode 100644 examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/ProviderSelectorTest.java delete mode 100644 examples/security/vaults/README.md delete mode 100644 examples/security/vaults/pom.xml delete mode 100644 examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/DigestService.java delete mode 100644 examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/EncryptionService.java delete mode 100644 examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/SecretsService.java delete mode 100644 examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/VaultsExampleMain.java delete mode 100644 examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/package-info.java delete mode 100644 examples/security/vaults/src/main/resources/application.yaml delete mode 100644 examples/security/vaults/src/main/resources/logging.properties delete mode 100644 examples/security/webserver-digest-auth/README.md delete mode 100644 examples/security/webserver-digest-auth/pom.xml delete mode 100644 examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderMain.java delete mode 100644 examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigMain.java delete mode 100644 examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleUtil.java delete mode 100644 examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/package-info.java delete mode 100644 examples/security/webserver-digest-auth/src/main/resources/application.yaml delete mode 100644 examples/security/webserver-digest-auth/src/main/resources/logging.properties delete mode 100644 examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderTest.java delete mode 100644 examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigTest.java delete mode 100644 examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleTest.java delete mode 100644 examples/security/webserver-signatures/README.md delete mode 100644 examples/security/webserver-signatures/pom.xml delete mode 100644 examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleBuilderMain.java delete mode 100644 examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleConfigMain.java delete mode 100644 examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleUtil.java delete mode 100644 examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/package-info.java delete mode 100644 examples/security/webserver-signatures/src/main/resources/keystore.p12 delete mode 100644 examples/security/webserver-signatures/src/main/resources/service1.yaml delete mode 100644 examples/security/webserver-signatures/src/main/resources/service2.yaml delete mode 100644 examples/security/webserver-signatures/src/test/java/io/helidon/security/examples/signatures/SignatureExampleBuilderMainTest.java delete mode 100644 examples/security/webserver-signatures/src/test/java/io/helidon/security/examples/signatures/SignatureExampleConfigMainTest.java delete mode 100644 examples/security/webserver-signatures/src/test/java/io/helidon/security/examples/signatures/SignatureExampleTest.java delete mode 100644 examples/todo-app/README.md delete mode 100644 examples/todo-app/backend/pom.xml delete mode 100644 examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/DbService.java delete mode 100644 examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/JaxRsBackendResource.java delete mode 100644 examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Main.java delete mode 100644 examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Todo.java delete mode 100644 examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/package-info.java delete mode 100644 examples/todo-app/backend/src/main/resources/META-INF/beans.xml delete mode 100644 examples/todo-app/backend/src/main/resources/application.yaml delete mode 100644 examples/todo-app/backend/src/main/resources/logging.properties delete mode 100644 examples/todo-app/backend/src/test/java/io/helidon/demo/todos/backend/BackendTests.java delete mode 100644 examples/todo-app/backend/src/test/resources/test-application.yaml delete mode 100644 examples/todo-app/cassandra/Dockerfile delete mode 100644 examples/todo-app/cassandra/startup.sh delete mode 100644 examples/todo-app/frontend/pom.xml delete mode 100644 examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/BackendServiceClient.java delete mode 100644 examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/Main.java delete mode 100644 examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/TodoService.java delete mode 100644 examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/package-info.java delete mode 100644 examples/todo-app/frontend/src/main/resources/WEB/css/styles.css delete mode 100644 examples/todo-app/frontend/src/main/resources/WEB/index.html delete mode 100644 examples/todo-app/frontend/src/main/resources/WEB/js/app.js delete mode 100644 examples/todo-app/frontend/src/main/resources/application.yaml delete mode 100644 examples/todo-app/frontend/src/main/resources/logging.properties delete mode 100644 examples/todo-app/frontend/src/test/java/io/helidon/demo/todos/frontend/TodoServiceTest.java delete mode 100644 examples/todo-app/frontend/src/test/resources/application-test.yaml delete mode 100644 examples/todo-app/pom.xml delete mode 100644 examples/translator-app/README.md delete mode 100644 examples/translator-app/backend/Dockerfile delete mode 100644 examples/translator-app/backend/app.yaml delete mode 100644 examples/translator-app/backend/pom.xml delete mode 100644 examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/Main.java delete mode 100644 examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/TranslatorBackendService.java delete mode 100644 examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/package-info.java delete mode 100644 examples/translator-app/backend/src/main/resources/logging.properties delete mode 100644 examples/translator-app/frontend/Dockerfile delete mode 100644 examples/translator-app/frontend/app.yaml delete mode 100644 examples/translator-app/frontend/pom.xml delete mode 100644 examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/Main.java delete mode 100644 examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/TranslatorFrontendService.java delete mode 100644 examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/package-info.java delete mode 100644 examples/translator-app/frontend/src/main/resources/logging.properties delete mode 100644 examples/translator-app/frontend/src/test/java/io/helidon/examples/translator/TranslatorTest.java delete mode 100644 examples/translator-app/pom.xml delete mode 100644 examples/webclient/pom.xml delete mode 100644 examples/webclient/standalone/README.md delete mode 100644 examples/webclient/standalone/pom.xml delete mode 100644 examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ClientMain.java delete mode 100644 examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/GreetService.java delete mode 100644 examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ServerMain.java delete mode 100644 examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/package-info.java delete mode 100644 examples/webclient/standalone/src/main/resources/application.yaml delete mode 100644 examples/webclient/standalone/src/main/resources/full-webclient-config.yaml delete mode 100644 examples/webclient/standalone/src/test/java/io/helidon/examples/webclient/standalone/ClientMainTest.java delete mode 100644 examples/webserver/README.md delete mode 100644 examples/webserver/basics/README.md delete mode 100644 examples/webserver/basics/pom.xml delete mode 100644 examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Catalog.java delete mode 100644 examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/HelloWorldResource.java delete mode 100644 examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Main.java delete mode 100644 examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Name.java delete mode 100644 examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/NameReader.java delete mode 100644 examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/package-info.java delete mode 100644 examples/webserver/basics/src/main/resources/static/index.html delete mode 100644 examples/webserver/basics/src/test/java/io/helidon/webserver/examples/basics/MainTest.java delete mode 100644 examples/webserver/comment-aas/README.md delete mode 100755 examples/webserver/comment-aas/etc/add-comment delete mode 100644 examples/webserver/comment-aas/etc/config.yaml delete mode 100755 examples/webserver/comment-aas/etc/create-etcd delete mode 100755 examples/webserver/comment-aas/etc/get-etcd-config delete mode 100755 examples/webserver/comment-aas/etc/list-comments delete mode 100755 examples/webserver/comment-aas/etc/put-etcd-config delete mode 100755 examples/webserver/comment-aas/etc/start-etcd delete mode 100755 examples/webserver/comment-aas/etc/stop-comment-service delete mode 100755 examples/webserver/comment-aas/etc/stop-etcd delete mode 100755 examples/webserver/comment-aas/etc/switch-user delete mode 100644 examples/webserver/comment-aas/pom.xml delete mode 100644 examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/CommentsService.java delete mode 100644 examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/Main.java delete mode 100644 examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityDetector.java delete mode 100644 examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityException.java delete mode 100644 examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/package-info.java delete mode 100644 examples/webserver/comment-aas/src/main/resources/application.yaml delete mode 100644 examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/CommentsServiceTest.java delete mode 100644 examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/MainTest.java delete mode 100644 examples/webserver/fault-tolerance/pom.xml delete mode 100644 examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/FtService.java delete mode 100644 examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/Main.java delete mode 100644 examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/package-info.java delete mode 100644 examples/webserver/fault-tolerance/src/main/resources/logging.properties delete mode 100644 examples/webserver/fault-tolerance/src/test/java/io/helidon/webserver/examples/faulttolerance/MainTest.java delete mode 100644 examples/webserver/jersey/README.md delete mode 100644 examples/webserver/jersey/pom.xml delete mode 100644 examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/HelloWorld.java delete mode 100644 examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/Main.java delete mode 100644 examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/package-info.java delete mode 100644 examples/webserver/jersey/src/main/resources/logging.properties delete mode 100644 examples/webserver/jersey/src/test/java/io/helidon/webserver/examples/jersey/HelloWorldTest.java delete mode 100644 examples/webserver/multiport/README.md delete mode 100644 examples/webserver/multiport/pom.xml delete mode 100644 examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/Main.java delete mode 100644 examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/package-info.java delete mode 100644 examples/webserver/multiport/src/main/resources/application.yaml delete mode 100644 examples/webserver/multiport/src/main/resources/logging.properties delete mode 100644 examples/webserver/multiport/src/test/java/io/helidon/examples/webserver/multiport/MainTest.java delete mode 100644 examples/webserver/multiport/src/test/resources/application-test.yaml delete mode 100644 examples/webserver/mutual-tls/README.md delete mode 100644 examples/webserver/mutual-tls/automatic-store-generator.sh delete mode 100644 examples/webserver/mutual-tls/pom.xml delete mode 100644 examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientBuilderMain.java delete mode 100644 examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientConfigMain.java delete mode 100644 examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerBuilderMain.java delete mode 100644 examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerConfigMain.java delete mode 100644 examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/package-info.java delete mode 100644 examples/webserver/mutual-tls/src/main/resources/application.yaml delete mode 100644 examples/webserver/mutual-tls/src/main/resources/client.p12 delete mode 100644 examples/webserver/mutual-tls/src/main/resources/server.p12 delete mode 100644 examples/webserver/mutual-tls/src/test/java/io/helidon/webserver/examples/mtls/MutualTlsExampleTest.java delete mode 100644 examples/webserver/mutual-tls/src/test/resources/application-test.yaml delete mode 100644 examples/webserver/opentracing/Dockerfile delete mode 100644 examples/webserver/opentracing/README.md delete mode 100644 examples/webserver/opentracing/pom.xml delete mode 100644 examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/Main.java delete mode 100644 examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/package-info.java delete mode 100644 examples/webserver/opentracing/src/main/resources/logging.properties delete mode 100644 examples/webserver/pom.xml delete mode 100644 examples/webserver/static-content/README.md delete mode 100644 examples/webserver/static-content/pom.xml delete mode 100644 examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/CounterService.java delete mode 100644 examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/Main.java delete mode 100644 examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/package-info.java delete mode 100644 examples/webserver/static-content/src/main/resources/WEB/css/app.css delete mode 100644 examples/webserver/static-content/src/main/resources/WEB/index.html delete mode 100644 examples/webserver/static-content/src/main/resources/WEB/js/app.js delete mode 100644 examples/webserver/streaming/README.md delete mode 100644 examples/webserver/streaming/pom.xml delete mode 100644 examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/Main.java delete mode 100644 examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/StreamingService.java delete mode 100644 examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/package-info.java delete mode 100644 examples/webserver/streaming/src/main/resources/large-file.bin delete mode 100644 examples/webserver/threadpool/README.md delete mode 100644 examples/webserver/threadpool/pom.xml delete mode 100644 examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/GreetService.java delete mode 100644 examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/Main.java delete mode 100644 examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/package-info.java delete mode 100644 examples/webserver/threadpool/src/main/resources/application.yaml delete mode 100644 examples/webserver/threadpool/src/main/resources/logging.properties delete mode 100644 examples/webserver/threadpool/src/test/java/io/helidon/examples/webserver/threadpool/MainTest.java delete mode 100644 examples/webserver/threadpool/src/test/resources/application-test.yaml delete mode 100644 examples/webserver/tls/pom.xml delete mode 100644 examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/Main.java delete mode 100644 examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/package-info.java delete mode 100644 examples/webserver/tls/src/main/resources/application.yaml delete mode 100644 examples/webserver/tls/src/main/resources/certificate.p12 delete mode 100644 examples/webserver/tls/src/main/resources/logging.properties delete mode 100644 examples/webserver/tls/src/test/java/io/helidon/webserver/examples/tls/MainTest.java delete mode 100644 examples/webserver/tls/src/test/resources/test-application.yaml delete mode 100644 examples/webserver/tutorial/README.md delete mode 100644 examples/webserver/tutorial/pom.xml delete mode 100644 examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/CommentService.java delete mode 100644 examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/Main.java delete mode 100644 examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/UpperXFilter.java delete mode 100644 examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/package-info.java delete mode 100644 examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/User.java delete mode 100644 examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/UserFilter.java delete mode 100644 examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/package-info.java delete mode 100644 examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/CommentServiceTest.java delete mode 100644 examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/MainTest.java delete mode 100644 examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/user/UserFilterTest.java delete mode 100644 examples/webserver/websocket/README.md delete mode 100644 examples/webserver/websocket/pom.xml delete mode 100644 examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/Main.java delete mode 100644 examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageBoardEndpoint.java delete mode 100644 examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueue.java delete mode 100644 examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueueService.java delete mode 100644 examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/package-info.java delete mode 100644 examples/webserver/websocket/src/main/resources/WEB/index.html delete mode 100644 examples/webserver/websocket/src/main/resources/logging.properties delete mode 100644 examples/webserver/websocket/src/test/java/io/helidon/webserver/examples/websocket/MessageBoardTest.java diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 1eeda35b42d..25a93894ca0 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -136,8 +136,7 @@ jobs: - name: Maven build run: | mvn -B -e "-Dmaven.test.skip=true" $MAVEN_HTTP_ARGS -DskipTests -Ppipeline install - cd examples - mvn -B verify + echo "TBD: validate examples from external repository" archetypes: timeout-minutes: 30 strategy: diff --git a/.gitignore b/.gitignore index 13c99b075c4..1c6856e6eed 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,9 @@ node/ # Helidon CLI .helidon +# Helidon examples repository +helidon-examples + # Other *~ user.txt diff --git a/etc/scripts/build-examples.sh b/etc/scripts/build-examples.sh new file mode 100755 index 00000000000..e5073563c2c --- /dev/null +++ b/etc/scripts/build-examples.sh @@ -0,0 +1,44 @@ +#!/bin/bash -e +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Build helidon examples, cloning the examples repository if needed + +# Path to this script +[ -h "${0}" ] && readonly SCRIPT_PATH="$(readlink "${0}")" || readonly SCRIPT_PATH="${0}" + +# Load pipeline environment setup and define WS_DIR +. $(dirname -- "${SCRIPT_PATH}")/includes/pipeline-env.sh "${SCRIPT_PATH}" '../..' + +# Setup error handling using default settings (defined in includes/error_handlers.sh) +error_trap_setup + +# If needed we clone the helidon-examples repo into a subdirectory of the helidon repository +readonly HELIDON_EXAMPLES_PATH=${WS_DIR}/helidon-examples +if [ ! -d "${HELIDON_EXAMPLES_PATH}" ]; then + echo "Cloning examples repository into ${HELIDON_EXAMPLES_PATH}" + git clone --branch dev-3.x --single-branch git@github.com:helidon-io/helidon-examples.git "${HELIDON_EXAMPLES_PATH}" +fi + +# Make sure the helidon version from the example repo aligns with this repository +readonly HELIDON_VERSION_IN_THIS_REPO=$(mvn --non-recursive -f ${WS_DIR}/pom.xml help:evaluate -Dexpression=helidon.version | grep -v '\[INFO\]') +readonly HELIDON_VERSION_IN_EXAMPLES=$(mvn --non-recursive -f ${HELIDON_EXAMPLES_PATH}/pom.xml help:evaluate -Dexpression=helidon.version | grep -v '\[INFO\]') +if [ ${HELIDON_VERSION_IN_THIS_REPO} != ${HELIDON_VERSION_IN_EXAMPLES} ]; then + echo "The Helidon version in this repository (${HELIDON_VERSION_IN_THIS_REPO}) does not match the Helidon version in ${HELIDON_EXAMPLES_PATH} (${HELIDON_VERSION_IN_EXAMPLES})" + exit 78 +fi + +mvn ${MAVEN_ARGS} -f ${HELIDON_EXAMPLES_PATH}/pom.xml clean install diff --git a/etc/scripts/checkstyle.sh b/etc/scripts/checkstyle.sh index 0ea1448c781..52c052e6ed9 100755 --- a/etc/scripts/checkstyle.sh +++ b/etc/scripts/checkstyle.sh @@ -1,6 +1,6 @@ #!/bin/bash -e # -# Copyright (c) 2018, 2022 Oracle and/or its affiliates. +# Copyright (c) 2018, 2024 Oracle and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ mvn ${MAVEN_ARGS} checkstyle:checkstyle-aggregate \ -f ${WS_DIR}/pom.xml \ -Dcheckstyle.output.format="plain" \ -Dcheckstyle.output.file="${RESULT_FILE}" \ - -Pexamples,ossrh-releases > ${LOG_FILE} 2>&1 || (cat ${LOG_FILE} ; exit 1) + -Possrh-releases > ${LOG_FILE} 2>&1 || (cat ${LOG_FILE} ; exit 1) grep "^\[ERROR\]" ${RESULT_FILE} \ && die "CHECKSTYLE ERROR" || echo "CHECKSTYLE OK" diff --git a/examples/README.md b/examples/README.md index abcc6419d9d..a5763c8a0dd 100644 --- a/examples/README.md +++ b/examples/README.md @@ -4,42 +4,5 @@ # Helidon Examples -Welcome to the Helidon Examples! If this is your first experience with -Helidon we recommend you start with our -[quickstart](https://helidon.io/docs/v2/#/about/03_prerequisites) -That will quickly get you going with your first Helidon application. +Helidon 3 examples have been moved to the [helidon-examples](https://github.com/helidon-io/helidon-examples/tree/helidon-3.x) repository. -After that you can come back here and dig into the examples. To access -these examples we recommend checking out from a released tag. For example: - -``` -git clone git@github.com:oracle/helidon.git -cd helidon -git checkout tags/2.0.0 -``` - -Our examples are Maven projects and can be built and run with -Java 11 or newer -- so make sure you have those: - -``` -java -version -mvn -version -``` - -# Building an Example - -Each example has a `README` that you will follow. To build most examples -just `cd` to the directory and run `mvn package`: - -``` -cd examples/microprofile/hello-world-explicit -mvn package -``` - -Usually the example will produce an application jar file that you can run: - -``` -java -jar target/example-name.jar -``` - -But always see the example's `README` for details. diff --git a/examples/config/README.md b/examples/config/README.md deleted file mode 100644 index 01555f3320c..00000000000 --- a/examples/config/README.md +++ /dev/null @@ -1,5 +0,0 @@ - -# Helidon SE Config Examples - -Each subdirectory contains example code that highlights specific aspects of -Helidon configuration. \ No newline at end of file diff --git a/examples/config/basics/README.md b/examples/config/basics/README.md deleted file mode 100644 index aa2aa316b1f..00000000000 --- a/examples/config/basics/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon Config Basic Example - -This example shows the basics of using Helidon SE Config. The -[Main.java](./src/main/java/io/helidon/config/examples/basics/Main.java) class shows: - -* loading configuration from a resource -[`application.conf`](./src/main/resources/application.conf) on the classpath -containing config in HOCON (Human-Optimized Config Object Notation) format -* getting configuration values of various types - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-config-basics.jar -``` diff --git a/examples/config/basics/pom.xml b/examples/config/basics/pom.xml deleted file mode 100644 index a917a767252..00000000000 --- a/examples/config/basics/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-basics - Helidon Config Examples Basics - - - The simplest example shows how to use Configuration API. - - - - io.helidon.config.examples.basics.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-hocon - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/basics/src/main/java/io/helidon/config/examples/basics/Main.java b/examples/config/basics/src/main/java/io/helidon/config/examples/basics/Main.java deleted file mode 100644 index b9b77b6b797..00000000000 --- a/examples/config/basics/src/main/java/io/helidon/config/examples/basics/Main.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.config.examples.basics; - -import java.nio.file.Path; -import java.util.List; - -import io.helidon.config.Config; - -import static io.helidon.config.ConfigSources.classpath; - -/** - * Basics example. - */ -public class Main { - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - Config config = Config.create(classpath("application.conf")); - - int pageSize = config.get("app.page-size").asInt().get(); - - boolean storageEnabled = config.get("app.storageEnabled").asBoolean().orElse(false); - - List basicRange = config.get("app.basic-range").asList(Integer.class).get(); - - Path loggingOutputPath = config.get("logging.outputs.file.name").as(Path.class).get(); - - System.out.println(pageSize); - System.out.println(storageEnabled); - System.out.println(basicRange); - System.out.println(loggingOutputPath); - } - -} diff --git a/examples/config/basics/src/main/java/io/helidon/config/examples/basics/package-info.java b/examples/config/basics/src/main/java/io/helidon/config/examples/basics/package-info.java deleted file mode 100644 index 0d1a22169e2..00000000000 --- a/examples/config/basics/src/main/java/io/helidon/config/examples/basics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The simplest example shows how to use Configuration API. - */ -package io.helidon.config.examples.basics; diff --git a/examples/config/basics/src/main/resources/application.conf b/examples/config/basics/src/main/resources/application.conf deleted file mode 100644 index 012af9e5c2d..00000000000 --- a/examples/config/basics/src/main/resources/application.conf +++ /dev/null @@ -1,69 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app { - greeting = "Hello" - name = "Demo" - page-size = 20 - basic-range = [ -20, 20 ] - storagePassphrase = "${AES=thisIsEncriptedPassphrase}" -} - -logging { - outputs { - console { - pattern = simple.colored - level = INFO - } - file { - pattern = verbose.colored - level = DEBUG - name = target/root.log - } - } - level = INFO - app.level = DEBUG - com.oracle.prime.level = WARN -} - -# (this is snippet of complex configuration of security component) -security { - providers: [ # First provider in the list is the default one - { - name = "BMCS" - class = "com.oracle.prime.security.bmcs.BmcsProvider" - BmcsProvider { - # Configuration of OPC (Bare metal) security provider - # (configuration cleaned to be short ...) - - # targets for outbound configuration - targets: [ - { - name = "s2s" - transports = ["http"] - hosts = ["127.0.0.1"] - s2sType = "S2S" - } - #, other targets ... - ] - } - }, - { - name = "ForEndUsers" - class = "com.oracle.prime.examples.security.primeruntime.bmcs.ExampleSecurityProvider" - } - ] -} diff --git a/examples/config/basics/src/main/resources/logging.properties b/examples/config/basics/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/basics/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/changes/README.md b/examples/config/changes/README.md deleted file mode 100644 index cdab258cdc5..00000000000 --- a/examples/config/changes/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Helidon Config Changes Example - -This example shows how an application can deal with changes to -configuration. - -## Change notification - -[`OnChangeExample.java`](./src/main/java/io/helidon/config/examples/changes/OnChangeExample.java): -uses `Config.onChange`, passing either a method reference (a lambda expression -would also work) which the config system invokes when the config source changes -) - -## Latest-value supplier - -Recall that once your application obtains a `Config` instance, its config values -do not change. The -[`AsSupplierExample.java`](./src/main/java/io/helidon/config/examples/changes/AsSupplierExample.java) -example shows how your application can get a config _supplier_ that always reports -the latest config value for a key, including any changes made after your -application obtained the `Config` object. Although this approach does not notify -your application _when_ changes occur, it _does_ permit your code to always use -the most up-to-date value. Sometimes that is all you need. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-config-changes.jar -``` diff --git a/examples/config/changes/conf/config.yaml b/examples/config/changes/conf/config.yaml deleted file mode 100644 index 000a60490c3..00000000000 --- a/examples/config/changes/conf/config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# In config.yaml we are going to override default configuration. -# It is supposed to be deployment dependent configuration. - -app: - greeting: Hello diff --git a/examples/config/changes/conf/dev.yaml b/examples/config/changes/conf/dev.yaml deleted file mode 100644 index 3d54809c0b4..00000000000 --- a/examples/config/changes/conf/dev.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# In dev.yaml we are going to override all lower layer configuration files. -# It is supposed to be development specific configuration. - -# IT SHOULD NOT BE PLACED IN VCS. EACH DEVELOPER CAN CUSTOMIZE THE FILE AS NEEDED. -# I.e. for example with GIT place following line into .gitignore file: -#*/conf/dev.yaml - -app: - name: Developer diff --git a/examples/config/changes/conf/secrets/password b/examples/config/changes/conf/secrets/password deleted file mode 100644 index 387f307495b..00000000000 --- a/examples/config/changes/conf/secrets/password +++ /dev/null @@ -1 +0,0 @@ -^ery$ecretP&ssword \ No newline at end of file diff --git a/examples/config/changes/conf/secrets/username b/examples/config/changes/conf/secrets/username deleted file mode 100644 index 1ce97e36c6b..00000000000 --- a/examples/config/changes/conf/secrets/username +++ /dev/null @@ -1 +0,0 @@ -libor \ No newline at end of file diff --git a/examples/config/changes/pom.xml b/examples/config/changes/pom.xml deleted file mode 100644 index 7a2574c2dc7..00000000000 --- a/examples/config/changes/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-changes - Helidon Config Examples Changes - - - The example shows how to use Configuration Changes API. - - - - io.helidon.config.examples.changes.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.common - helidon-common-reactive - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/changes/src/main/java/io/helidon/config/examples/changes/AsSupplierExample.java b/examples/config/changes/src/main/java/io/helidon/config/examples/changes/AsSupplierExample.java deleted file mode 100644 index d1113130fef..00000000000 --- a/examples/config/changes/src/main/java/io/helidon/config/examples/changes/AsSupplierExample.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2017, 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.config.examples.changes; - -import java.time.Duration; -import java.util.Objects; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.config.FileSystemWatcher; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; -import static io.helidon.config.PollingStrategies.regular; - -/** - * Example shows how to use Config accessor methods that return {@link Supplier}. - * {@link Supplier} returns always the last loaded config value. - *

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

- * The feature is based on using {@link io.helidon.config.spi.PollingStrategy} with - * selected config source(s) to check for changes. - */ -public class OnChangeExample { - - private static final Logger LOGGER = Logger.getLogger(OnChangeExample.class.getName()); - - /** - * Executes the example. - */ - public void run() { - Config secrets = Config - .builder(ConfigSources.directory("conf/secrets") - .pollingStrategy(PollingStrategies.regular(ofSeconds(5)))) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - - logSecrets(secrets); - - // subscribe using simple onChange consumer -- could be a lambda as well - secrets.onChange(OnChangeExample::logSecrets); - } - - private static void logSecrets(Config secrets) { - LOGGER.info("Loaded secrets are u: " + secrets.get("username").asString().get() - + ", p: " + secrets.get("password").asString().get()); - } - -} diff --git a/examples/config/changes/src/main/java/io/helidon/config/examples/changes/package-info.java b/examples/config/changes/src/main/java/io/helidon/config/examples/changes/package-info.java deleted file mode 100644 index a8576e63d54..00000000000 --- a/examples/config/changes/src/main/java/io/helidon/config/examples/changes/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The example shows how to use Configuration Changes API. - */ -package io.helidon.config.examples.changes; diff --git a/examples/config/changes/src/main/resources/default.yaml b/examples/config/changes/src/main/resources/default.yaml deleted file mode 100644 index c4f334a3bb0..00000000000 --- a/examples/config/changes/src/main/resources/default.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# In default.yaml we are going to configure application default values. -# It is expected it is overridden in: -# - conf/config.yaml in production environment -# - conf/dev.yaml by developer on local machine - -app: - greeting: Hi - name: Example diff --git a/examples/config/changes/src/main/resources/logging.properties b/examples/config/changes/src/main/resources/logging.properties deleted file mode 100644 index 31bc145f8d8..00000000000 --- a/examples/config/changes/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/git/README.md b/examples/config/git/README.md deleted file mode 100644 index 17317d06410..00000000000 --- a/examples/config/git/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Helidon Config Git Example - -This example shows how to load configuration from a Git repository -and switch which branch to load from at runtime. - -## Prerequisites - -The example assumes that the GitHub repository -has a branch named `test` that contains `application.conf` which sets the key -`greeting` to value `hello`. (The Helidon team has created and populated this -repository.) - -The code in [`Main.java`](./src/main/java/io/helidon/config/examples/git/Main.java) -uses the environment variable `ENVIRONMENT_NAME` to fetch the branch name -in the GitHub repository to use; it uses `master` by default (which does _not_ -contain the expected value). - -The example application constructs a `Config` instance from that file in the -GitHub repository and branch, prints out the value for key `greeting`, and -checks to make sure the value is the expected `hello`. - -## Build and run - -```bash -mvn package -export ENVIRONMENT_NAME=test -java -jar target/helidon-examples-config-git.jar -``` diff --git a/examples/config/git/pom.xml b/examples/config/git/pom.xml deleted file mode 100644 index 2bc0d404beb..00000000000 --- a/examples/config/git/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-git - Helidon Config Examples Git - - - The example shows how to use GitConfigSource. - - - - io.helidon.config.examples.git.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-hocon - - - io.helidon.config - helidon-config-git - - - org.slf4j - slf4j-jdk14 - - - - - - - org.codehaus.mojo - exec-maven-plugin - - - test - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/git/src/main/java/io/helidon/config/examples/git/Main.java b/examples/config/git/src/main/java/io/helidon/config/examples/git/Main.java deleted file mode 100644 index 1af5b17e0c6..00000000000 --- a/examples/config/git/src/main/java/io/helidon/config/examples/git/Main.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2017, 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.config.examples.git; - -import java.io.IOException; -import java.net.URI; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.git.GitConfigSource; - -/** - * Git source example. - *

- * This example expects: - *

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

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

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

- * {@link Value} is used to specify correct config key and default value supplier - * in case configuration does not contain appropriate value. - * Supplier already returns default value in target type of a property. - * - * @param basicRange basic range - */ - @Value(key = "basic-range", withDefaultSupplier = DefaultBasicRangeSupplier.class) - public void setBasicRange(List basicRange) { - this.basicRange = basicRange; - } - - /** - * Creates new instance of {@link AppConfig} using values provided by configuration. - * - * @return new instance of {@link AppConfig}. - */ - public AppConfig build() { - return new AppConfig(greeting, pageSize, basicRange); - } - } - - /** - * Supplier of default value for {@link Builder#setBasicRange(List) basic-range} property. - */ - public static class DefaultBasicRangeSupplier implements Supplier> { - @Override - public List get() { - return List.of(-10, 10); - } - } - } -} diff --git a/examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/DeserializationExample.java b/examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/DeserializationExample.java deleted file mode 100644 index ec00769c7d7..00000000000 --- a/examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/DeserializationExample.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.config.examples.mapping; - -import java.util.List; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.objectmapping.Value; - -/** - * This example shows how to automatically deserialize configuration instance into POJO beans - * using setters. - */ -public class DeserializationExample { - - private DeserializationExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - Config config = Config.create(ConfigSources.classpath("application.conf")); - - AppConfig appConfig = config - // get "app" sub-node - .get("app") - // let config automatically deserialize the node to new AppConfig instance - .as(AppConfig.class) - .get(); - - System.out.println(appConfig); - - // assert values loaded from application.conf - - assert appConfig.getGreeting().equals("Hello"); - - assert appConfig.getPageSize() == 20; - - assert appConfig.getBasicRange().size() == 2; - assert appConfig.getBasicRange().get(0) == -20; - assert appConfig.getBasicRange().get(1) == 20; - } - - /** - * POJO representing an application configuration. - * Class is initialized from {@link Config} instance. - * During deserialization setter methods are invoked. - */ - public static class AppConfig { - private String greeting; - private int pageSize; - private List basicRange; - - public String getGreeting() { - return greeting; - } - - /** - * Set greeting property. - *

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

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

- * {@link Value} is used to specify correct config key and default value supplier - * in case configuration does not contain appropriate value. - * Supplier already returns default value in target type of a property. - * - * @param basicRange basic range - */ - @Value(key = "basic-range", withDefaultSupplier = DefaultBasicRangeSupplier.class) - public void setBasicRange(List basicRange) { - this.basicRange = basicRange; - } - - @Override - public String toString() { - return "AppConfig:\n" - + " greeting = " + greeting + "\n" - + " pageSize = " + pageSize + "\n" - + " basicRange= " + basicRange; - } - - /** - * Supplier of default value for {@link #setBasicRange(List) basic-range} property. - */ - public static class DefaultBasicRangeSupplier implements Supplier> { - @Override - public List get() { - return List.of(-10, 10); - } - } - } -} diff --git a/examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/FactoryMethodExample.java b/examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/FactoryMethodExample.java deleted file mode 100644 index 1b681b0428f..00000000000 --- a/examples/config/mapping/src/main/java/io/helidon/config/examples/mapping/FactoryMethodExample.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.config.examples.mapping; - -import java.util.List; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.objectmapping.Value; - -/** - * This example shows how to automatically deserialize configuration instance into POJO beans - * using factory method. - */ -public class FactoryMethodExample { - - private FactoryMethodExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - Config config = Config.create(ConfigSources.classpath("application.conf")); - - AppConfig appConfig = config - // get "app" sub-node - .get("app") - // let config automatically deserialize the node to new AppConfig instance - .as(AppConfig.class) - .get(); - - System.out.println(appConfig); - - // assert values loaded from application.conf - - assert appConfig.getGreeting().equals("Hello"); - - assert appConfig.getPageSize() == 20; - - assert appConfig.getBasicRange().size() == 2; - assert appConfig.getBasicRange().get(0) == -20; - assert appConfig.getBasicRange().get(1) == 20; - } - - /** - * POJO representing an application configuration. - * Class is initialized from {@link Config} instance. - * During deserialization {@link #create(String, int, List) factory method} is invoked. - */ - public static class AppConfig { - private final String greeting; - private final int pageSize; - private final List basicRange; - - private AppConfig(String greeting, int pageSize, List basicRange) { - this.greeting = greeting; - this.pageSize = pageSize; - this.basicRange = basicRange; - } - - public String getGreeting() { - return greeting; - } - - public int getPageSize() { - return pageSize; - } - - public List getBasicRange() { - return basicRange; - } - - @Override - public String toString() { - return "AppConfig:\n" - + " greeting = " + greeting + "\n" - + " pageSize = " + pageSize + "\n" - + " basicRange= " + basicRange; - } - - /** - * Creates new {@link AppConfig} instances. - *

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

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

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

- * prod:
- *   abcdef:
- *     logging:
- *     level: ERROR
- *     app:
- *       greeting:  Ahoy
- *       page-size: 42
- *       basic-range:
- *         - -20
- *         -  20
- * 
- * But the override source just overrides values for environment: {@code prod} and pod: {@code abcdef} (it is the first - * overriding rule found) and value for key {@code prod.abcdef.logging.level = FINEST}. For completeness, we would say that the - * other pods in {@code prod} environment has overridden config value {@code prod.*.logging.level} to {@code WARNING} and all - * pods - * {@code test.*.logging.level} to {@code FINE}. - */ -public final class Main { - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - * @throws InterruptedException when a sleeper awakes - */ - public static void main(String... args) throws InterruptedException { - Config config = Config - .builder() - // specify config sources - .sources(file("conf/priority-config.yaml").pollingStrategy(regular(Duration.ofSeconds(1))), - classpath("application.yaml")) - // specify overrides source - .overrides(OverrideSources.file("conf/overrides.properties") - .pollingStrategy(regular(Duration.ofSeconds(1)))) - .build(); - - // Resolve current runtime context - String env = config.get("env").asString().get(); - String pod = config.get("pod").asString().get(); - - // get logging config for the current runtime - Config loggingConfig = config - .get(env) - .get(pod) - .get("logging"); - - // initialize logging from config - initLogging(loggingConfig); - - // react on changes of logging configuration - loggingConfig.onChange(Main::initLogging); - - TimeUnit.MINUTES.sleep(1); - } - - /** - * Initialize logging from config. - */ - private static void initLogging(Config loggingConfig) { - String level = loggingConfig.get("level").asString().orElse("WARNING"); - //e.g. initialize logging using configured level... - - System.out.println("Set logging level to " + level + "."); - } - -} diff --git a/examples/config/overrides/src/main/java/io/helidon/config/examples/overrides/package-info.java b/examples/config/overrides/src/main/java/io/helidon/config/examples/overrides/package-info.java deleted file mode 100644 index 2b2c9b4fbe1..00000000000 --- a/examples/config/overrides/src/main/java/io/helidon/config/examples/overrides/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The example shows how to use Overrides in Configuration API. - */ -package io.helidon.config.examples.overrides; diff --git a/examples/config/overrides/src/main/resources/application.yaml b/examples/config/overrides/src/main/resources/application.yaml deleted file mode 100644 index b0c0c55f9ca..00000000000 --- a/examples/config/overrides/src/main/resources/application.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# default context - -env: dev -pod: local - -# app config -# key format: $env.$pod... - -$env: - $pod: - logging: - level: CONFIG - - app: - greeting: Hello - page-size: 20 - basic-range: - - -20 - - 20 diff --git a/examples/config/overrides/src/main/resources/logging.properties b/examples/config/overrides/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/overrides/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/pom.xml b/examples/config/pom.xml deleted file mode 100644 index 5ddfc093aef..00000000000 --- a/examples/config/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.config - helidon-examples-config-project - pom - Helidon Config Examples - - - basics - changes - git - mapping - overrides - sources - profiles - metadata - - - diff --git a/examples/config/profiles/README.md b/examples/config/profiles/README.md deleted file mode 100644 index 8c98e3308cc..00000000000 --- a/examples/config/profiles/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Helidon Config Profiles Example - -This example shows how to load configuration from multiple -configuration sources using profiles. - -This example contains the following profiles: - -1. no profile - if you start the application with no profile, the usual `src/main/resources/application.yaml` will be used -2. `local` - `src/main/resources/application-local.yaml` will be used -3. `dev` - has an explicit profile file `config-profile-dev.yaml` on classpath that defines an inlined configuration -4. `stage` - has an explicit profile file `config-profile-stage.yaml` on classpath that defines a classpath config source -4. `prod` - has an explicit profile file `config-profile-prod.yaml` on file system that defines a path config source - -To switch profiles -- either use a system property `config.profile` -- or use an environment variable `HELIDON_CONFIG_PROFILE` - - -## How to run this example: - -Build the application -```shell -mvn clean package -``` - -Run it with a profile -```shell -java -Dconfig.profile=prod -jar target/helidon-examples-config-profiles.jar -``` - -Changing the profile name should use different configuration. \ No newline at end of file diff --git a/examples/config/profiles/config-profile-prod.yaml b/examples/config/profiles/config-profile-prod.yaml deleted file mode 100644 index f0cf375cc49..00000000000 --- a/examples/config/profiles/config-profile-prod.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -sources: - - type: "environment-variables" - - type: "system-properties" - - type: "file" - properties: - path: "config/config-prod.yaml" diff --git a/examples/config/profiles/config/config-prod.yaml b/examples/config/profiles/config/config-prod.yaml deleted file mode 100644 index ee020122c09..00000000000 --- a/examples/config/profiles/config/config-prod.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -message: "config/config-prod.yaml" diff --git a/examples/config/profiles/pom.xml b/examples/config/profiles/pom.xml deleted file mode 100644 index e2d1940921a..00000000000 --- a/examples/config/profiles/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-profiles - Helidon Config Examples Profiles - - - The example shows how to use Config Profiles (meta configuration). - - - - io.helidon.examples.config.profiles.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/Main.java b/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/Main.java deleted file mode 100644 index 0077a16939d..00000000000 --- a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/Main.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.config.profiles; - -import io.helidon.config.Config; - -/** - * Example main class. - */ -public final class Main { - private Main() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - Config config = Config.create(); - - System.out.println("Configured message: " + config.get("message").asString().orElse("MISSING")); - } -} diff --git a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/package-info.java b/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/package-info.java deleted file mode 100644 index bb7cb9ee79e..00000000000 --- a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example showing usage of configuration profiles in Helidon SE. - */ -package io.helidon.examples.config.profiles; diff --git a/examples/config/profiles/src/main/resources/application-local.yaml b/examples/config/profiles/src/main/resources/application-local.yaml deleted file mode 100644 index f54597e9d16..00000000000 --- a/examples/config/profiles/src/main/resources/application-local.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -message: "src/main/resources/application-local.yaml" diff --git a/examples/config/profiles/src/main/resources/application-stage.yaml b/examples/config/profiles/src/main/resources/application-stage.yaml deleted file mode 100644 index 7343ff57108..00000000000 --- a/examples/config/profiles/src/main/resources/application-stage.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -message: "src/main/resources/application-stage.yaml" diff --git a/examples/config/profiles/src/main/resources/application.yaml b/examples/config/profiles/src/main/resources/application.yaml deleted file mode 100644 index 3eee73c1582..00000000000 --- a/examples/config/profiles/src/main/resources/application.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -message: "src/main/resources/application.yaml" diff --git a/examples/config/profiles/src/main/resources/config-profile-dev.yaml b/examples/config/profiles/src/main/resources/config-profile-dev.yaml deleted file mode 100644 index 345d2f00304..00000000000 --- a/examples/config/profiles/src/main/resources/config-profile-dev.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -sources: - - type: "inlined" - properties: - message: "inlined in dev profile" diff --git a/examples/config/profiles/src/main/resources/config-profile-stage.yaml b/examples/config/profiles/src/main/resources/config-profile-stage.yaml deleted file mode 100644 index 9740180c872..00000000000 --- a/examples/config/profiles/src/main/resources/config-profile-stage.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -sources: - - type: "classpath" - properties: - resource: "application-stage.yaml" diff --git a/examples/config/sources/README.md b/examples/config/sources/README.md deleted file mode 100644 index 27e20509842..00000000000 --- a/examples/config/sources/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon Config Sources Example - -This example shows how to load configuration from multiple -configuration sources. - -1. [`DirectorySourceExample.java`](./src/main/java/io/helidon/config/examples/sources/DirectorySourceExample.java) -reads configuration from multiple files in a directory by specifying only the directory. -2. [`LoadSourcesExample.java`](./src/main/java/io/helidon/config/examples/sources/LoadSourcesExample.java) -uses _meta-configuration_ files [`conf/meta-config.yaml`](./conf/meta-config.yaml) -and [`src/main/resources/meta-config.yaml`](./src/main/resources/meta-config.yaml) -which contain not the configuration itself but -_instructions for loading_ the configuration: what type, from where, etc. It also -applies a filter to modify config values whose keys match a certain pattern. -3. [`WithSourcesExample.java`](./src/main/java/io/helidon/config/examples/sources/WithSourcesExample.java) -combines multiple config sources into a single configuration instance (and adds a -filter. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-config-sources.jar -``` diff --git a/examples/config/sources/conf/config.yaml b/examples/config/sources/conf/config.yaml deleted file mode 100644 index c0794062841..00000000000 --- a/examples/config/sources/conf/config.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# In config.yaml we are going to override default configuration. -# It is supposed to be deployment dependent configuration. - -meta: - env: PROD - -app: - page-size: 10 - diff --git a/examples/config/sources/conf/dev.yaml b/examples/config/sources/conf/dev.yaml deleted file mode 100644 index 10ca8dc5fdd..00000000000 --- a/examples/config/sources/conf/dev.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# In dev.yaml we are going to override all lower layer configuration files. -# It is supposed to be development specific configuration. - -# IT SHOULD NOT BE PLACED IN VCS. EACH DEVELOPER CAN CUSTOMIZE THE FILE AS NEEDED. -# I.e. for example with GIT place following line into .gitignore file: -#*/conf/dev.yaml - -meta: - env: DEV - -component: - audit: - logging: - level: fine diff --git a/examples/config/sources/conf/meta-config.yaml b/examples/config/sources/conf/meta-config.yaml deleted file mode 100644 index 3153da4a79c..00000000000 --- a/examples/config/sources/conf/meta-config.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -sources: - - type: "environment-variables" - - type: "system-properties" - - type: "file" - properties: - path: "conf/dev.yaml" - optional: true - - type: "file" - properties: - path: "conf/config.yaml" - optional: true - - type: "classpath" - properties: - resource: "default.yaml" diff --git a/examples/config/sources/conf/secrets/password b/examples/config/sources/conf/secrets/password deleted file mode 100644 index 387f307495b..00000000000 --- a/examples/config/sources/conf/secrets/password +++ /dev/null @@ -1 +0,0 @@ -^ery$ecretP&ssword \ No newline at end of file diff --git a/examples/config/sources/conf/secrets/username b/examples/config/sources/conf/secrets/username deleted file mode 100644 index 1ce97e36c6b..00000000000 --- a/examples/config/sources/conf/secrets/username +++ /dev/null @@ -1 +0,0 @@ -libor \ No newline at end of file diff --git a/examples/config/sources/pom.xml b/examples/config/sources/pom.xml deleted file mode 100644 index 646974344f8..00000000000 --- a/examples/config/sources/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-sources - Helidon Config Examples Sources - - - This example shows how to merge the configuration from different sources. - - - - io.helidon.config.examples.sources.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/DirectorySourceExample.java b/examples/config/sources/src/main/java/io/helidon/config/examples/sources/DirectorySourceExample.java deleted file mode 100644 index 6f469ac998f..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/DirectorySourceExample.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.config.examples.sources; - -import io.helidon.config.Config; - -import static io.helidon.config.ConfigSources.directory; - -/** - * This example shows how to read configuration from several files placed in selected directory. - */ -public class DirectorySourceExample { - - private DirectorySourceExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - /* - Creates a config from files from specified directory. - E.g. Kubernetes Secrets: - */ - - Config secrets = Config.builder(directory("conf/secrets")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - - String username = secrets.get("username").asString().get(); - System.out.println("Username: " + username); - assert username.equals("libor"); - - String password = secrets.get("password").asString().get(); - System.out.println("Password: " + password); - assert password.equals("^ery$ecretP&ssword"); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/LoadSourcesExample.java b/examples/config/sources/src/main/java/io/helidon/config/examples/sources/LoadSourcesExample.java deleted file mode 100644 index ead744ce6a1..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/LoadSourcesExample.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.config.examples.sources; - -import io.helidon.config.Config; -import io.helidon.config.ConfigValue; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * This example shows how to merge the configuration from different sources - * loaded from meta configuration. - * - * @see WithSourcesExample - */ -public class LoadSourcesExample { - - private LoadSourcesExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - /* - Creates a configuration from list of config sources loaded from meta sources: - - conf/meta-config.yaml - - deployment dependent meta-config file, loaded from file on filesystem; - - meta-config.yaml - application default meta-config file, loaded form classpath; - with a filter which convert values with keys ending with "level" to upper case - */ - - Config metaConfig = Config.create(file("conf/meta-config.yaml").optional(), - classpath("meta-config.yaml")); - - Config config = Config.builder() - .config(metaConfig) - .addFilter((key, stringValue) -> key.name().equals("level") ? stringValue.toUpperCase() : stringValue) - .build(); - - // Optional environment type, from dev.yaml: - ConfigValue env = config.get("meta.env").asString(); - env.ifPresent(e -> System.out.println("Environment: " + e)); - assert env.get().equals("DEV"); - - // Default value (default.yaml): Config Sources Example - String appName = config.get("app.name").asString().get(); - System.out.println("Name: " + appName); - assert appName.equals("Config Sources Example"); - - // Page size, from config.yaml: 10 - int pageSize = config.get("app.page-size").asInt().get(); - System.out.println("Page size: " + pageSize); - assert pageSize == 10; - - // Applied filter (uppercase logging level), from dev.yaml: finest -> FINEST - String level = config.get("component.audit.logging.level").asString().get(); - System.out.println("Level: " + level); - assert level.equals("FINE"); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/Main.java b/examples/config/sources/src/main/java/io/helidon/config/examples/sources/Main.java deleted file mode 100644 index bea16ec6dec..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/Main.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.config.examples.sources; - -/** - * Runs every example main class in this module/package. - */ -public class Main { - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String[] args) { - WithSourcesExample.main(args); - LoadSourcesExample.main(args); - DirectorySourceExample.main(args); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/WithSourcesExample.java b/examples/config/sources/src/main/java/io/helidon/config/examples/sources/WithSourcesExample.java deleted file mode 100644 index 8de8a3aaaa9..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/WithSourcesExample.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.config.examples.sources; - -import io.helidon.config.Config; -import io.helidon.config.ConfigValue; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * This example shows how to merge the configuration from different sources. - * - * @see LoadSourcesExample - */ -public class WithSourcesExample { - - private WithSourcesExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - /* - Creates a config source composed of following sources: - - conf/dev.yaml - developer specific configuration, should not be placed in VCS; - - conf/config.yaml - deployment dependent configuration, for example prod, stage, etc; - - default.yaml - application default values, loaded form classpath; - with a filter which convert values with keys ending with "level" to upper case - */ - - Config config = Config - .builder(file("conf/dev.yaml").optional(), - file("conf/config.yaml").optional(), - classpath("default.yaml")) - .addFilter((key, stringValue) -> key.name().equals("level") ? stringValue.toUpperCase() : stringValue) - .build(); - - // Environment type, from dev.yaml: - ConfigValue env = config.get("meta.env").asString(); - env.ifPresent(e -> System.out.println("Environment: " + e)); - assert env.get().equals("DEV"); - - // Default value (default.yaml): Config Sources Example - String appName = config.get("app.name").asString().get(); - System.out.println("Name: " + appName); - assert appName.equals("Config Sources Example"); - - // Page size, from config.yaml: 10 - int pageSize = config.get("app.page-size").asInt().get(); - System.out.println("Page size: " + pageSize); - assert pageSize == 10; - - // Applied filter (uppercase logging level), from dev.yaml: finest -> FINEST - String level = config.get("component.audit.logging.level").asString().get(); - System.out.println("Level: " + level); - assert level.equals("FINE"); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/package-info.java b/examples/config/sources/src/main/java/io/helidon/config/examples/sources/package-info.java deleted file mode 100644 index 44958945786..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/config/examples/sources/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This example shows how to merge the configuration from different sources. - */ -package io.helidon.config.examples.sources; diff --git a/examples/config/sources/src/main/resources/default.yaml b/examples/config/sources/src/main/resources/default.yaml deleted file mode 100644 index 94a8de205eb..00000000000 --- a/examples/config/sources/src/main/resources/default.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# In default.yaml we are going to configure application default values. -# It is expected it is overridden in: -# - conf/config.yaml in production environment -# - conf/dev.yaml by developer on local machine - -app: - name: Config Sources Example - page-size: 20 - -component: - audit: - logging: - level: info - monitoring: - logging: - level: warning diff --git a/examples/config/sources/src/main/resources/logging.properties b/examples/config/sources/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/sources/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/sources/src/main/resources/meta-config.yaml b/examples/config/sources/src/main/resources/meta-config.yaml deleted file mode 100644 index 20af0f805f0..00000000000 --- a/examples/config/sources/src/main/resources/meta-config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# ordered list of sources -sources: - - type: "classpath" - properties: - resource: "default.yaml" diff --git a/examples/config/sources/src/main/resources/overrides.properties b/examples/config/sources/src/main/resources/overrides.properties deleted file mode 100644 index 717a177f19d..00000000000 --- a/examples/config/sources/src/main/resources/overrides.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -component.*.logging.level = finest diff --git a/examples/cors/README.md b/examples/cors/README.md deleted file mode 100644 index e32f6d9cd26..00000000000 --- a/examples/cors/README.md +++ /dev/null @@ -1,169 +0,0 @@ - -# Helidon SE CORS Example - -This example shows a simple greeting application, similar to the one from the -Helidon SE QuickStart, enhanced with CORS support. - -Look at the `resources/application.yaml` file and notice the `restrictive-cors` -section. (We'll come back to the `cors` section later.) The `Main#corsSupportForGreeting` method loads this -configuration and uses it to set up CORS for the application's endpoints. - -Near the end of the `resources/logging.properties` file, a commented line would turn on `FINE -` logging that would reveal how the Helidon CORS support makes it decisions. To see that logging, -uncomment that line and then package and run the application. - -## Build and run - -With JDK11+ -```bash -mvn package -java -jar helidon-examples-cors.jar -``` - -## Using the app endpoints as with the "classic" greeting app - -These normal greeting app endpoints work just as in the original greeting app: - -```bash -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} -``` - -## Using CORS - -### Sending "simple" CORS requests - -The following requests illustrate the CORS protocol with the example app. - -By setting `Origin` and `Host` headers that do not indicate the same system we trigger CORS processing in the - server: - -```bash -# Follow the CORS protocol for GET -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet - -HTTP/1.1 200 OK -Access-Control-Allow-Origin: * -Content-Type: application/json -Date: Thu, 30 Apr 2020 17:25:51 -0500 -Vary: Origin -connection: keep-alive -content-length: 27 - -{"greeting":"Hola World!"} -``` -Note the new headers `Access-Control-Allow-Origin` and `Vary` in the response. - -The same happens for a `GET` requesting a personalized greeting (by passing the name of the - person to be greeted): -```bash -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe -{"greeting":"Hola Joe!"} -``` -These two `GET` requests work because the `Main#corsSupportForGreeting` method adds a default `CrossOriginConfig` to the -`CorsSupport.Builder` it sets up. This is in addition to adding a `CrossOriginConfig` based on the `restrictive-cors` -configuration in `application.yaml` we looked at earlier. - -These are what CORS calls "simple" requests; the CORS protocol for these adds headers to the request and response which -the client and server exchange anyway. - -### "Non-simple" CORS requests - -The CORS protocol requires the client to send a _pre-flight_ request before sending a request - that changes state on the server, such as `PUT` or `DELETE`, and to check the returned status - and headers to make sure the server is willing to accept the actual request. CORS refers to such `PUT` and `DELETE` - requests as "non-simple" ones. - -This command sends a pre-flight `OPTIONS` request to see if the server will accept a subsequent `PUT` request from the -specified origin to change the greeting: -```bash -curl -i -X OPTIONS \ - -H "Access-Control-Request-Method: PUT" \ - -H "Origin: http://foo.com" \ - -H "Host: here.com" \ - http://localhost:8080/greet/greeting - -HTTP/1.1 200 OK -Access-Control-Allow-Methods: PUT -Access-Control-Allow-Origin: http://foo.com -Date: Thu, 30 Apr 2020 17:30:59 -0500 -transfer-encoding: chunked -connection: keep-alive -``` -The successful status and the returned `Access-Control-Allow-xxx` headers indicate that the - server accepted the pre-flight request. That means it is OK for us to send `PUT` request to perform the actual change - of greeting. (See below for how the server rejects a pre-flight request.) -```bash -curl -i -X PUT \ - -H "Origin: http://foo.com" \ - -H "Host: here.com" \ - -H "Access-Control-Allow-Methods: PUT" \ - -H "Access-Control-Allow-Origin: http://foo.com" \ - -H "Content-Type: application/json" \ - -d "{ \"greeting\" : \"Cheers\" }" \ - http://localhost:8080/greet/greeting - -HTTP/1.1 204 No Content -Access-Control-Allow-Origin: http://foo.com -Date: Thu, 30 Apr 2020 17:32:55 -0500 -Vary: Origin -connection: keep-alive -``` -And we run one more `GET` to observe the change in the greeting: -```bash -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe -{"greeting":"Cheers Joe!"} -``` -Note that the tests in the example `MainTest` class follow these same steps. - -## Using overrides - -The `Main#corsSupportForGreeting` method loads override settings for any other CORS set-up if the config contains a -"cors" section. (That section is initially commented out in the example `application.yaml` file.) Not all applications -need this feature, but the example shows how easy it is to add. - -With the same server running, repeat the `OPTIONS` request from above, but change the `Origin` header to refer to -`other.com`: -```bash -curl -i -X OPTIONS \ - -H "Access-Control-Request-Method: PUT" \ - -H "Origin: http://other.com" \ - -H "Host: here.com" \ - http://localhost:8080/greet/greeting -HTTP/1.1 403 Forbidden -Date: Mon, 4 May 2020 10:49:41 -0500 -transfer-encoding: chunked -connection: keep-alive -``` -This fails because the app set up CORS using the "restrictive-cors" configuration in `application.yaml` which allows -sharing only with `foo.com` and `there.com`, not with `other.com`. - -Stop the running app, uncomment the commented section at the end of `application.yaml`, and build and run the app again. -```bash -mvn package -java -jar helidon-examples-cors.jar -``` -Send the previous `OPTIONS` request again and note the successful result: -```bash -HTTP/1.1 200 OK -Access-Control-Allow-Methods: PUT -Access-Control-Allow-Origin: http://other.com -Access-Control-Max-Age: 3600 -Date: Mon, 4 May 2020 18:52:54 -0500 -transfer-encoding: chunked -connection: keep-alive -``` -The application uses the now-uncommented portion of the config file to override the rest of the CORS set-up. You can -choose whatever key name you want for the override. Just make sure you tell your end users whatever the key is your app -uses for overrides. - -A real application might read the normal configuration (`restrictive-cors`) from one config source and any overrides -from another. This example combines them in one config source just for simplicity. \ No newline at end of file diff --git a/examples/cors/pom.xml b/examples/cors/pom.xml deleted file mode 100644 index ad15e8dc071..00000000000 --- a/examples/cors/pom.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../applications/se/pom.xml - - io.helidon.examples - helidon-examples-cors - Helidon SE Examples CORS - - - Basic illustration of CORS support in Helidon SE - - - - io.helidon.examples.cors.Main - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver - helidon-webserver-cors - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/GreetService.java b/examples/cors/src/main/java/io/helidon/examples/cors/GreetService.java deleted file mode 100644 index 5463f226503..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/GreetService.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.cors; - -import java.util.Collections; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonReaderFactory; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private static final JsonReaderFactory JSON_RF = Json.createReaderFactory(Collections.emptyMap()); - - GreetService(Config config) { - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - } - - /** - * A service registers itself by updating the routine rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - GreetingMessage msg = new GreetingMessage(String.format("%s %s!", greeting, name)); - response.send(msg.forRest()); - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey(GreetingMessage.JSON_LABEL)) { - JsonObject jsonErrorObject = JSON_BF.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting = GreetingMessage.fromRest(jo).getMessage(); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class).thenAccept(jo -> updateGreetingFromJson(jo, response)); - } -} diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/GreetingMessage.java b/examples/cors/src/main/java/io/helidon/examples/cors/GreetingMessage.java deleted file mode 100644 index 63b835069b6..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/GreetingMessage.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.cors; - -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * POJO for the greeting message exchanged between the server and the client. - */ -public class GreetingMessage { - - /** - * Label for tagging a {@code GreetingMessage} instance in JSON. - */ - public static final String JSON_LABEL = "greeting"; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private String message; - - /** - * Create a new greeting with the specified message content. - * - * @param message the message to store in the greeting - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Returns the message value. - * - * @return the message - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message value to be set - */ - public void setMessage(String message) { - this.message = message; - } - - /** - * Converts a JSON object (typically read from the request payload) - * into a {@code GreetingMessage}. - * - * @param jsonObject the {@link JsonObject} to convert. - * @return {@code GreetingMessage} set according to the provided object - */ - public static GreetingMessage fromRest(JsonObject jsonObject) { - return new GreetingMessage(jsonObject.getString(JSON_LABEL)); - } - - /** - * Prepares a {@link JsonObject} corresponding to this instance. - * - * @return {@code JsonObject} representing this {@code GreetingMessage} instance - */ - public JsonObject forRest() { - JsonObjectBuilder builder = JSON_BF.createObjectBuilder(); - return builder.add(JSON_LABEL, message) - .build(); - } -} diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/Main.java b/examples/cors/src/main/java/io/helidon/examples/cors/Main.java deleted file mode 100644 index b2c033abd80..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/Main.java +++ /dev/null @@ -1,138 +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. - */ - -package io.helidon.examples.cors; - -import java.io.IOException; -import java.util.logging.Logger; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.cors.CorsSupport; -import io.helidon.webserver.cors.CrossOriginConfig; - -/** - * Simple Hello World rest application. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - * @throws IOException if there are problems reading logging properties - */ - public static void main(final String[] args) throws IOException { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - * @throws IOException if there are problems reading logging properties - */ - static Single startServer() throws IOException { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // Get webserver config from the "server" section of application.yaml - Single server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build() - .start(); - - server.thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - return server; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - GreetService greetService = new GreetService(config); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - // Note: Add the CORS routing *before* registering the GreetService routing. - return Routing.builder() - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register("/greet", corsSupportForGreeting(config), greetService) - .build(); - } - - private static CorsSupport corsSupportForGreeting(Config config) { - - // The default CorsSupport object (obtained using CorsSupport.create()) allows sharing for any HTTP method and with any - // origin. Using CorsSupport.create(Config) with a missing config node yields a default CorsSupport, which might not be - // what you want. This example warns if either expected config node is missing and then continues with the default. - - Config restrictiveConfig = config.get("restrictive-cors"); - if (!restrictiveConfig.exists()) { - Logger.getLogger(Main.class.getName()) - .warning("Missing restrictive config; continuing with default CORS support"); - } - - CorsSupport.Builder corsBuilder = CorsSupport.builder(); - - // Use possible overrides first. - config.get("cors") - .ifExists(c -> { - Logger.getLogger(Main.class.getName()).info("Using the override configuration"); - corsBuilder.mappedConfig(c); - }); - corsBuilder - .config(restrictiveConfig) // restricted sharing for PUT, DELETE - .addCrossOrigin(CrossOriginConfig.create()) // open sharing for other methods - .build(); - - return corsBuilder.build(); - } -} diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/package-info.java b/examples/cors/src/main/java/io/helidon/examples/cors/package-info.java deleted file mode 100644 index 37ff772213f..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example application showing CORS support in Helidon SE - *

- * Start with {@link io.helidon.examples.cors.Main} class. - * - * @see io.helidon.examples.cors.Main - */ -package io.helidon.examples.cors; diff --git a/examples/cors/src/main/resources/META-INF/openapi.yml b/examples/cors/src/main/resources/META-INF/openapi.yml deleted file mode 100644 index 1d733567079..00000000000 --- a/examples/cors/src/main/resources/META-INF/openapi.yml +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---- -openapi: 3.0.0 -info: - title: Helidon SE Quickstart Example - description: A very simple application to reply with friendly greetings - version: 1.0.0 - -servers: - - url: http://localhost:8000 - description: Local test server - -paths: - /greet: - get: - summary: Returns a generic greeting - description: Greets the user generically - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - /greet/greeting: - put: - summary: Set the greeting prefix - description: Permits the client to set the prefix part of the greeting ("Hello") - requestBody: - description: Conveys the new greeting prefix to use in building greetings - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - examples: - greeting: - summary: Example greeting message to update - value: New greeting message - responses: - "200": - description: OK - content: - application/json: {} - /greet/{name}: - get: - summary: Returns a personalized greeting - parameters: - - name: name - in: path - required: true - schema: - type: string - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' -components: - schemas: - GreetingMessage: - properties: - message: - type: string diff --git a/examples/cors/src/main/resources/application.yaml b/examples/cors/src/main/resources/application.yaml deleted file mode 100644 index eea832f731a..00000000000 --- a/examples/cors/src/main/resources/application.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - -restrictive-cors: - allow-origins: ["http://foo.com", "http://there.com"] - allow-methods: ["PUT", "DELETE"] - -# The the example app uses the following for overriding other settings. -#cors: -# paths: -# - path-pattern: /greeting -# allow-origins: ["http://foo.com", "http://there.com", "http://other.com"] -# allow-methods: ["PUT", "DELETE"] - diff --git a/examples/cors/src/main/resources/logging.properties b/examples/cors/src/main/resources/logging.properties deleted file mode 100644 index bb63a07aa78..00000000000 --- a/examples/cors/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Uncomment the following to see CORS-related decision-making -# io.helidon.webserver.cors.level=FINE diff --git a/examples/cors/src/test/java/io/helidon/examples/cors/MainTest.java b/examples/cors/src/test/java/io/helidon/examples/cors/MainTest.java deleted file mode 100644 index a26eb056ad0..00000000000 --- a/examples/cors/src/test/java/io/helidon/examples/cors/MainTest.java +++ /dev/null @@ -1,245 +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. - */ - -package io.helidon.examples.cors; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Headers; -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientRequestBuilder; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.cors.CrossOriginConfig; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsEmptyCollection.empty; - -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - - @BeforeAll - public static void start() throws Exception { - // the port is only available if the server started already! - // so we need to wait - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - - long timeout = 2000; // 2 seconds should be enough to start the server - long now = System.currentTimeMillis(); - - while (!webServer.isRunning()) { - Thread.sleep(100); - if ((System.currentTimeMillis() - now) > timeout) { - Assertions.fail("Failed to start webserver"); - } - } - } - - @AfterAll - public static void stop() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - @Order(1) // Make sure this runs before the greeting message changes so responses are deterministic. - @Test - public void testHelloWorld() { - - WebClientResponse r = getResponse("/greet"); - - assertThat("HTTP response1", r.status().code(), is(200)); - assertThat("default message", fromPayload(r).getMessage(), - is("Hello World!")); - - r = getResponse("/greet/Joe"); - assertThat("HTTP response2", r.status().code(), is(200)); - assertThat("hello Joe message", fromPayload(r).getMessage(), - is("Hello Joe!")); - - r = putResponse("/greet/greeting", new GreetingMessage("Hola")); - assertThat("HTTP response3", r.status().code(), is(204)); - - r = getResponse("/greet/Jose"); - assertThat( "HTTP response4", r.status().code(), is(200)); - assertThat("hola Jose message", fromPayload(r).getMessage(), - is("Hola Jose!")); - - r = getResponse("/health"); - assertThat("HTTP response2", r.status().code(), is(200)); - - r = getResponse("/metrics"); - assertThat( "HTTP response2", r.status().code(), is(200)); - } - - @Order(10) // Run after the non-CORS tests (so the greeting is Hola) but before the CORS test that changes the greeting again. - @Test - void testAnonymousGreetWithCors() { - WebClientRequestBuilder builder = webClient.get(); - Headers headers = builder.headers(); - headers.add("Origin", "http://foo.com"); - headers.add("Host", "here.com"); - - WebClientResponse r = getResponse("/greet", builder); - assertThat("HTTP response", r.status().code(), is(200)); - String payload = fromPayload(r).getMessage(); - assertThat("HTTP response payload was " + payload, payload, containsString("Hola World")); - headers = r.headers(); - Optional allowOrigin = headers.value(CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN + " is absent", - allowOrigin.isPresent(), is(true)); - assertThat(allowOrigin.get(), is("*")); - } - - @Order(11) // Run after the non-CORS tests but before other CORS tests. - @Test - void testGreetingChangeWithCors() { - - // Send the pre-flight request and check the response. - - WebClientRequestBuilder builder = webClient.options(); - Headers headers = builder.headers(); - headers.add("Origin", "http://foo.com"); - headers.add("Host", "here.com"); - headers.add("Access-Control-Request-Method", "PUT"); - - WebClientResponse r = builder.path("/greet/greeting") - .submit() - .await(); - - Headers preflightResponseHeaders = r.headers(); - List allowMethods = preflightResponseHeaders.values(CrossOriginConfig.ACCESS_CONTROL_ALLOW_METHODS); - assertThat("pre-flight response does not include " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_METHODS, - allowMethods, not(empty())); - assertThat(allowMethods, hasItem("PUT")); - List allowOrigins = preflightResponseHeaders.values(CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("pre-flight response does not include " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN, - allowOrigins, not(empty())); - assertThat("Header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN - + " should contain '*' but does not; " + allowOrigins, - allowOrigins, hasItem("http://foo.com")); - - // Send the follow-up request. - - builder = webClient.put(); - headers = builder.headers(); - headers.add("Origin", "http://foo.com"); - headers.add("Host", "here.com"); - headers.addAll(preflightResponseHeaders); - - r = putResponse("/greet/greeting", new GreetingMessage("Cheers"), builder); - assertThat("HTTP response3", r.status().code(), is(204)); - headers = r.headers(); - allowOrigins = headers.values(CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN + " has no value(s)", - allowOrigins, not(empty())); - assertThat("Header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN - + " should contain '*' but does not; " + allowOrigins, - allowOrigins, hasItem("http://foo.com")); - } - - @Order(12) // Run after CORS test changes greeting to Cheers. - @Test - void testNamedGreetWithCors() { - WebClientRequestBuilder builder = webClient.get(); - Headers headers = builder.headers(); - headers.add("Origin", "http://foo.com"); - headers.add("Host", "here.com"); - - WebClientResponse r = getResponse("/greet/Maria", builder); - assertThat("HTTP response", r.status().code(), is(200)); - assertThat(fromPayload(r).getMessage(), containsString("Cheers Maria")); - headers = r.headers(); - Optional allowOrigin = headers.value(CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN + " is absent", - allowOrigin.isPresent(), is(true)); - assertThat(allowOrigin.get(), is("*")); - } - - @Order(100) // After all other tests so we can rely on deterministic greetings. - @Test - void testGreetingChangeWithCorsAndOtherOrigin() { - WebClientRequestBuilder builder = webClient.put(); - Headers headers = builder.headers(); - headers.add("Origin", "http://other.com"); - headers.add("Host", "here.com"); - - WebClientResponse r = putResponse("/greet/greeting", new GreetingMessage("Ahoy"), builder); - // Result depends on whether we are using overrides or not. - boolean isOverriding = Config.create().get("cors").exists(); - assertThat("HTTP response3", r.status().code(), is(isOverriding ? 204 : 403)); - } - - private static WebClientResponse getResponse(String path) { - return getResponse(path, webClient.get()); - } - - private static WebClientResponse getResponse(String path, WebClientRequestBuilder builder) { - return builder - .accept(MediaType.APPLICATION_JSON) - .path(path) - .submit() - .await(); - } - - private static WebClientResponse putResponse(String path, GreetingMessage payload) { - return putResponse(path, payload, webClient.put()); - } - - private static WebClientResponse putResponse(String path, GreetingMessage payload, WebClientRequestBuilder builder) { - return builder - .accept(MediaType.APPLICATION_JSON) - .path(path) - .submit(payload.forRest()) - .await(); - } - - private static GreetingMessage fromPayload(WebClientResponse response) { - JsonObject json = response - .content() - .as(JsonObject.class) - .await(); - - return GreetingMessage.fromRest(json); - } -} diff --git a/examples/dbclient/README.md b/examples/dbclient/README.md deleted file mode 100644 index db4dc973ba4..00000000000 --- a/examples/dbclient/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Helidon DB Client Examples - -Each subdirectory contains example code that highlights specific aspects of -Helidon DB Client. - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/common/pom.xml b/examples/dbclient/common/pom.xml deleted file mode 100644 index a4e938d7803..00000000000 --- a/examples/dbclient/common/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.dbclient - helidon-examples-dbclient-project - 3.2.7-SNAPSHOT - - - helidon-examples-dbclient-common - Helidon Examples DB Client Common - - - - io.helidon.dbclient - helidon-dbclient - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/AbstractPokemonService.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/AbstractPokemonService.java deleted file mode 100644 index 0baee49fea8..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/AbstractPokemonService.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.common; - -import java.util.concurrent.CompletionException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.common.reactive.Multi; -import io.helidon.common.reactive.Single; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.webserver.Handler; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.JsonObject; - -/** - * Common methods that do not differ between JDBC and MongoDB. - */ -public abstract class AbstractPokemonService implements Service { - private static final Logger LOGGER = Logger.getLogger(AbstractPokemonService.class.getName()); - - private final DbClient dbClient; - - /** - * Create a new pokemon service with a DB client. - * - * @param dbClient DB client to use for database operations - */ - protected AbstractPokemonService(DbClient dbClient) { - this.dbClient = dbClient; - } - - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::listPokemons) - // create new - .put("/", Handler.create(Pokemon.class, this::insertPokemon)) - // update existing - .post("/{name}/type/{type}", this::insertPokemonSimple) - // delete all - .delete("/", this::deleteAllPokemons) - // get one - .get("/{name}", this::getPokemon) - // delete one - .delete("/{name}", this::deletePokemon) - // example of transactional API (local transaction only!) - .put("/transactional", Handler.create(Pokemon.class, this::transactional)) - // update one (TODO this is intentionally wrong - should use JSON request, just to make it simple we use path) - .put("/{name}/type/{type}", this::updatePokemonType); - } - - /** - * The DB client associated with this service. - * - * @return DB client instance - */ - protected DbClient dbClient() { - return dbClient; - } - - /** - * This method is left unimplemented to show differences between native statements that can be used. - * - * @param request Server request - * @param response Server response - */ - protected abstract void deleteAllPokemons(ServerRequest request, ServerResponse response); - - /** - * Insert new pokemon with specified name. - * - * @param request the server request - * @param response the server response - */ - private void insertPokemon(ServerRequest request, ServerResponse response, Pokemon pokemon) { - dbClient.execute(exec -> exec - .createNamedInsert("insert2") - .namedParam(pokemon) - .execute()) - .thenAccept(count -> response.send("Inserted: " + count + " values")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Insert new pokemon with specified name. - * - * @param request the server request - * @param response the server response - */ - private void insertPokemonSimple(ServerRequest request, ServerResponse response) { - // Test Pokemon POJO mapper - Pokemon pokemon = new Pokemon(request.path().param("name"), request.path().param("type")); - - dbClient.execute(exec -> exec - .createNamedInsert("insert2") - .namedParam(pokemon) - .execute()) - .thenAccept(count -> response.send("Inserted: " + count + " values")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Get a single pokemon by name. - * - * @param request server request - * @param response server response - */ - private void getPokemon(ServerRequest request, ServerResponse response) { - String pokemonName = request.path().param("name"); - - dbClient.execute(exec -> exec.namedGet("select-one", pokemonName)) - .thenAccept(opt -> opt.ifPresentOrElse(it -> sendRow(it, response), - () -> sendNotFound(response, "Pokemon " - + pokemonName - + " not found"))) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Return JsonArray with all stored pokemons or pokemons with matching attributes. - * - * @param request the server request - * @param response the server response - */ - private void listPokemons(ServerRequest request, ServerResponse response) { - Multi rows = dbClient.execute(exec -> exec.namedQuery("select-all")) - .map(it -> it.as(JsonObject.class)); - - response.send(rows, JsonObject.class); - } - - /** - * Update a pokemon. - * Uses a transaction. - * - * @param request the server request - * @param response the server response - */ - private void updatePokemonType(ServerRequest request, ServerResponse response) { - final String name = request.path().param("name"); - final String type = request.path().param("type"); - - dbClient.execute(exec -> exec - .createNamedUpdate("update") - .addParam("name", name) - .addParam("type", type) - .execute()) - .thenAccept(count -> response.send("Updated: " + count + " values")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - private void transactional(ServerRequest request, ServerResponse response, Pokemon pokemon) { - - dbClient.inTransaction(tx -> tx - .createNamedGet("select-for-update") - .namedParam(pokemon) - .execute() - .flatMapSingle(maybeRow -> maybeRow.map(dbRow -> tx.createNamedUpdate("update") - .namedParam(pokemon).execute()) - .orElseGet(() -> Single.just(0L))) - ).thenAccept(count -> response.send("Updated " + count + " records")); - - } - - /** - * Delete pokemon with specified name (key). - * - * @param request the server request - * @param response the server response - */ - private void deletePokemon(ServerRequest request, ServerResponse response) { - final String name = request.path().param("name"); - - dbClient.execute(exec -> exec.namedDelete("delete", name)) - .thenAccept(count -> response.send("Deleted: " + count + " values")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Send a 404 status code. - * - * @param response the server response - * @param message entity content - */ - protected void sendNotFound(ServerResponse response, String message) { - response.status(Http.Status.NOT_FOUND_404); - response.send(message); - } - - /** - * Send a single DB row as JSON object. - * - * @param row row as read from the database - * @param response server response - */ - protected void sendRow(DbRow row, ServerResponse response) { - response.send(row.as(JsonObject.class)); - } - - /** - * Send a 500 response code and a few details. - * - * @param throwable throwable that caused the issue - * @param response server response - * @param type of expected response, will be always {@code null} - * @return {@code Void} so this method can be registered as a lambda - * with {@link java.util.concurrent.CompletionStage#exceptionally(java.util.function.Function)} - */ - protected T sendError(Throwable throwable, ServerResponse response) { - Throwable realCause = throwable; - if (throwable instanceof CompletionException) { - realCause = throwable.getCause(); - } - response.status(Http.Status.INTERNAL_SERVER_ERROR_500); - response.send("Failed to process request: " + realCause.getClass().getName() + "(" + realCause.getMessage() + ")"); - LOGGER.log(Level.WARNING, "Failed to process request", throwable); - return null; - } - -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/Pokemon.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/Pokemon.java deleted file mode 100644 index c50a8793037..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/Pokemon.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.common; - -import io.helidon.common.Reflected; - -/** - * POJO representing a very simplified Pokemon. - */ -@Reflected -public class Pokemon { - private String name; - private String type; - - /** - * Default constructor. - */ - public Pokemon() { - // JSON-B - } - - /** - * Create pokemon with name and type. - * - * @param name name of the beast - * @param type type of the beast - */ - public Pokemon(String name, String type) { - this.name = name; - this.type = type; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapper.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapper.java deleted file mode 100644 index 7bc17a14336..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapper.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.common; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbColumn; -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -/** - * Maps database statements to {@link io.helidon.examples.dbclient.common.Pokemon} class. - */ -public class PokemonMapper implements DbMapper { - - @Override - public Pokemon read(DbRow row) { - DbColumn name = row.column("name"); - // we know that in mongo this is not true - if (null == name) { - name = row.column("_id"); - } - - DbColumn type = row.column("type"); - return new Pokemon(name.as(String.class), type.as(String.class)); - } - - @Override - public Map toNamedParameters(Pokemon value) { - Map map = new HashMap<>(1); - map.put("name", value.getName()); - map.put("type", value.getType()); - return map; - } - - @Override - public List toIndexedParameters(Pokemon value) { - List list = new ArrayList<>(2); - list.add(value.getName()); - list.add(value.getType()); - return list; - } -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapperProvider.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapperProvider.java deleted file mode 100644 index eafbc23428d..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapperProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.common; - -import java.util.Optional; - -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.spi.DbMapperProvider; - -import jakarta.annotation.Priority; - -/** - * Provides pokemon mappers. - */ -@Priority(1000) -public class PokemonMapperProvider implements DbMapperProvider { - private static final PokemonMapper MAPPER = new PokemonMapper(); - - @SuppressWarnings("unchecked") - @Override - public Optional> mapper(Class type) { - if (type.equals(Pokemon.class)) { - return Optional.of((DbMapper) MAPPER); - } - return Optional.empty(); - } -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/package-info.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/package-info.java deleted file mode 100644 index 7e0afe5d8d0..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Common classes shared by JDBC and MongoDB examples. - */ -package io.helidon.examples.dbclient.common; diff --git a/examples/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider b/examples/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider deleted file mode 100644 index b292790974c..00000000000 --- a/examples/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -io.helidon.examples.dbclient.common.PokemonMapperProvider diff --git a/examples/dbclient/jdbc/README.md b/examples/dbclient/jdbc/README.md deleted file mode 100644 index d78895e3eeb..00000000000 --- a/examples/dbclient/jdbc/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Helidon DB Client JDBC Example - -This example shows how to run Helidon DB Client over JDBC. - -Examples are given for H2, Oracle, or MySQL databases (note that MySQL is currently not supported for GraalVM native image) - -Uncomment the appropriate dependencies in the pom.xml for the desired database (H2, Oracle, or MySQL) and insure others are commented. - -Uncomment the appropriate configuration in the application.xml for the desired database (H2, Oracle, or MySQL) and insure others are commented. - -## Build - -``` -mvn package -``` - -This example may also be run as a GraalVM native image in which case can be built using the following: - -``` -mvn package -Pnative-image -``` - - -## Run - -This example requires a database. - -Instructions for H2 can be found here: http://www.h2database.com/html/cheatSheet.html - -Instructions for Oracle can be found here: https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance - -MySQL can be run as a docker container with the following command: -``` -docker run --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=pokemon -e MYSQL_USER=user -e MYSQL_PASSWORD=password mysql:5.7 -``` - - -Then run the application: - -``` -java -jar target/helidon-examples-dbclient-jdbc.jar -``` -or in the case of native image -``` -./target/helidon-examples-dbclient-jdbc -``` - -## Exercise - -The application has the following endpoints: - -- http://localhost:8079/db - the main business endpoint (see `curl` commands below) -- http://localhost:8079/metrics - the metrics endpoint (query adds application metrics) -- http://localhost:8079/health - has a custom database health check - -Application also connects to zipkin on default address. -The query operation adds database trace. - -`curl` commands: - -- `curl http://localhost:8079/db` - list all Pokemon in the database -- `curl -i -X PUT -d '{"name":"Squirtle","type":"water"}' http://localhost:8079/db` - add a new pokemon -- `curl http://localhost:8079/db/Squirtle` - get a single pokemon - -The application also supports update and delete - see `PokemonService.java` for bound endpoints. - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/jdbc/pom.xml b/examples/dbclient/jdbc/pom.xml deleted file mode 100644 index c78516144be..00000000000 --- a/examples/dbclient/jdbc/pom.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-dbclient-jdbc - Helidon Examples DB Client JDBC - - - io.helidon.examples.dbclient.jdbc.JdbcExampleMain - - - - - io.helidon.health - helidon-health - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing - helidon-tracing-zipkin - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.dbclient - helidon-dbclient-tracing - - - io.helidon.dbclient - helidon-dbclient-metrics - - - io.helidon.dbclient - helidon-dbclient-metrics-jdbc - - - io.helidon.dbclient - helidon-dbclient-health - - - io.helidon.dbclient - helidon-dbclient-jsonp - - - - - - io.helidon.integrations.db - ojdbc - - - - org.slf4j - slf4j-jdk14 - - - io.helidon.media - helidon-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.examples.dbclient - helidon-examples-dbclient-common - ${project.version} - - - io.helidon.metrics - helidon-metrics - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/JdbcExampleMain.java b/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/JdbcExampleMain.java deleted file mode 100644 index 079d234fb92..00000000000 --- a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/JdbcExampleMain.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.dbclient.jdbc; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.health.HealthSupport; -import io.helidon.media.jsonb.JsonbSupport; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Simple Hello World rest application. - */ -public final class JdbcExampleMain { - - /** - * Cannot be instantiated. - */ - private JdbcExampleMain() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link io.helidon.webserver.WebServer} instance - */ - static WebServer startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // Prepare routing for the server - WebServer server = WebServer.builder() - .routing(createRouting(config)) - // Get webserver config from the "server" section of application.yaml - .config(config.get("server")) - .tracer(TracerBuilder.create(config.get("tracing"))) - .addMediaSupport(JsonpSupport.create()) - .addMediaSupport(JsonbSupport.create()) - .build(); - - // Start the server and print some info. - server.start().thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/"); - }); - - // Server threads are not daemon. NO need to block. Just react. - server.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - - return server; - } - - /** - * Creates new {@link io.helidon.webserver.Routing}. - * - * @param config configuration of this server - * @return routing configured with JSON support, a health check, and a service - */ - private static Routing createRouting(Config config) { - Config dbConfig = config.get("db"); - - // Client services are added through a service loader - see mongoDB example for explicit services - DbClient dbClient = DbClient.builder(dbConfig) - .build(); - - // Some relational databases do not support DML statement as ping so using query which works for all of them - HealthSupport health = HealthSupport.builder() - .addLiveness( - DbClientHealthCheck.create(dbClient, dbConfig.get("health-check"))) - .build(); - - return Routing.builder() - .register(health) // Health at "/health" - .register(MetricsSupport.create()) // Metrics at "/metrics" - .register("/db", new PokemonService(dbClient)) - .build(); - } -} diff --git a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/PokemonService.java b/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/PokemonService.java deleted file mode 100644 index 445e416931b..00000000000 --- a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/PokemonService.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.dbclient.jdbc; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.dbclient.DbClient; -import io.helidon.examples.dbclient.common.AbstractPokemonService; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; - -/** - * Example service using a database. - */ -public class PokemonService extends AbstractPokemonService { - private static final Logger LOGGER = Logger.getLogger(PokemonService.class.getName()); - - PokemonService(DbClient dbClient) { - super(dbClient); - - // dirty hack to prepare database for our POC - // MySQL init - dbClient.execute(handle -> handle.namedDml("create-table")) - .thenAccept(System.out::println) - .exceptionally(throwable -> { - LOGGER.log(Level.WARNING, "Failed to create table, maybe it already exists?", throwable); - return null; - }); - } - - /** - * Delete all pokemons. - * - * @param request the server request - * @param response the server response - */ - @Override - protected void deleteAllPokemons(ServerRequest request, ServerResponse response) { - dbClient().execute(exec -> exec - // this is to show how ad-hoc statements can be executed (and their naming in Tracing and Metrics) - .createDelete("DELETE FROM pokemons") - .execute()) - .thenAccept(count -> response.send("Deleted: " + count + " values")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - - - - -} diff --git a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/package-info.java b/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/package-info.java deleted file mode 100644 index 13fdc00a70d..00000000000 --- a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quick start demo application. - */ -package io.helidon.examples.dbclient.jdbc; diff --git a/examples/dbclient/jdbc/src/main/resources/application.yaml b/examples/dbclient/jdbc/src/main/resources/application.yaml deleted file mode 100644 index 2f1cefc9476..00000000000 --- a/examples/dbclient/jdbc/src/main/resources/application.yaml +++ /dev/null @@ -1,108 +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. -# - -server: - port: 8079 - host: 0.0.0.0 - features: - print-details: true - -tracing: - service: jdbc-db - -db: - source: jdbc - connection: - # - # H2 configuration - # - # Embedded mode (does not work with native image) -# url: jdbc:h2:~/test - # Server mode, run: docker run --rm --name h2 -p 9092:9082 -p 8082:8082 nemerosa/h2 -# url: "jdbc:h2:tcp://localhost:9092/~test" -# username: sa -# password: -# poolName: h2 - # - # MySQL configuration - # - # docker run --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root \ - # -e MYSQL_DATABASE=pokemon -e MYSQL_USER=user -e MYSQL_PASSWORD=password mysql:5.7 -# url: jdbc:mysql://127.0.0.1:3306/pokemon?useSSL=false -# username: user -# password: password -# poolName: mysql - # - # Oracle configuration - # - # docker run --rm --name xe -p 1521:1521 -p 8888:8080 -e ORACLE_PWD=oracle wnameless/oracle-xe-11g-r2 - url: jdbc:oracle:thin:@localhost:1521/XE - username: system - password: oracle - poolName: oracle - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - health-check: - type: "query" - statementName: "health-check" - services: - tracing: - # would trace all statement names that start with select- - - statement-names: ["select-.*"] - # would trace all delete statements - - statement-types: ["DELETE"] - metrics: - - type: METER - name-format: "db.meter.overall" - - type: METER - # meter per statement name (default name format) - - type: METER - # meter per statement type - name-format: "db.meter.%1$s" - - type: TIMER - errors: false - statement-names: ["select-.*"] - description: "Timer for successful selects" - - type: COUNTER - errors: false - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - name-format: "db.counter.%s.success" - description: "Counter of successful DML statements" - - type: COUNTER - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - success: false - name-format: "db.counter.%s.error" - description: "Counter of failed DML statements" - statements: - # Health check query statement for MySQL and H2 databases -# health-check: "SELECT 0" - # Health check query statement for Oracle database - health-check: "SELECT 1 FROM DUAL" - # Insert new pokemon - create-table: "CREATE TABLE pokemons (name VARCHAR(64) NOT NULL PRIMARY KEY, type VARCHAR(32))" - insert1: "INSERT INTO pokemons VALUES(?, ?)" - insert2: "INSERT INTO pokemons VALUES(:name, :type)" - select-by-type: "SELECT * FROM pokemons WHERE type = ?" - select-one: "SELECT * FROM pokemons WHERE name = ?" - select-all: "SELECT * FROM pokemons" - select-for-update: "SELECT * FROM pokemons WHERE name = :name for UPDATE" - update: "UPDATE pokemons SET type = :type WHERE name = :name" - delete: "DELETE FROM pokemons WHERE name = ?" diff --git a/examples/dbclient/jdbc/src/main/resources/logging.properties b/examples/dbclient/jdbc/src/main/resources/logging.properties deleted file mode 100644 index a3b94c39c5f..00000000000 --- a/examples/dbclient/jdbc/src/main/resources/logging.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# Global default logging level. Can be overriden by specific handlers and loggers -.level=INFO - -# Helidon Web Server has a custom log formatter that extends SimpleFormatter. -# It replaces "!thread!" with the current thread name -io.helidon.common.HelidonConsoleHandler.level=ALL -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/dbclient/mongodb/README.md b/examples/dbclient/mongodb/README.md deleted file mode 100644 index 5c1b78034ba..00000000000 --- a/examples/dbclient/mongodb/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Helidon DB Client mongoDB Example - -This example shows how to run Helidon DB over mongoDB. - - -## Build - -``` -mvn package -``` - -## Run - -This example requires a mongoDB database, start it using docker: - -``` -docker run --rm --name mongo -p 27017:27017 mongo -``` - -Then run the application: - -``` -java -jar target/helidon-examples-dbclient-mongodb.jar -``` - - -## Exercise - -The application has the following endpoints: - -- http://localhost:8079/db - the main business endpoint (see `curl` commands below) -- http://localhost:8079/metrics - the metrics endpoint (query adds application metrics) -- http://localhost:8079/health - has a custom database health check - -Application also connects to zipkin on default address. -The query operation adds database trace. - -`curl` commands: - -- `curl http://localhost:8079/db` - list all Pokemon in the database -- `curl -i -X PUT -d '{"name":"Squirtle","type":"water"}' http://localhost:8079/db` - add a new pokemon -- `curl http://localhost:8079/db/Squirtle` - get a single pokemon -- `curl -i -X DELETE http://localhost:8079/db/Squirtle` - delete a single pokemon -- `curl -i -X DELETE http://localhost:8079/db` - delete all pokemon - -The application also supports update and delete - see `PokemonService.java` for bound endpoints. - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/mongodb/pom.xml b/examples/dbclient/mongodb/pom.xml deleted file mode 100644 index bcb23825ce9..00000000000 --- a/examples/dbclient/mongodb/pom.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-dbclient-mongodb - Helidon Examples DB Client MongoDB - - - io.helidon.examples.dbclient.mongo.MongoDbExampleMain - - - - - io.helidon.common - helidon-common - - - io.helidon.common - helidon-common-mapper - - - io.helidon.dbclient - helidon-dbclient-mongodb - - - io.helidon.dbclient - helidon-dbclient-tracing - - - io.helidon.dbclient - helidon-dbclient-metrics - - - io.helidon.dbclient - helidon-dbclient-health - - - io.helidon.dbclient - helidon-dbclient-jsonp - - - io.helidon.health - helidon-health - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing - helidon-tracing-zipkin - - - io.helidon.media - helidon-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.examples.dbclient - helidon-examples-dbclient-common - ${project.version} - - - io.helidon.metrics - helidon-metrics - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/MongoDbExampleMain.java b/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/MongoDbExampleMain.java deleted file mode 100644 index 70a11fd4bd4..00000000000 --- a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/MongoDbExampleMain.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.dbclient.mongo; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbStatementType; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.dbclient.metrics.DbClientMetrics; -import io.helidon.dbclient.tracing.DbClientTracing; -import io.helidon.health.HealthSupport; -import io.helidon.media.jsonb.JsonbSupport; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Simple Hello World rest application. - */ -public final class MongoDbExampleMain { - - /** - * Cannot be instantiated. - */ - private MongoDbExampleMain() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link io.helidon.webserver.WebServer} instance - */ - static WebServer startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .tracer(TracerBuilder.create("mongo-db").build()) - .addMediaSupport(JsonpSupport.create()) - .addMediaSupport(JsonbSupport.create()) - .build(); - - // Start the server and print some info. - server.start().thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/"); - }); - - // Server threads are not daemon. NO need to block. Just react. - server.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - - return server; - } - - /** - * Creates new {@link io.helidon.webserver.Routing}. - * - * @param config configuration of this server - * @return routing configured with JSON support, a health check, and a service - */ - private static Routing createRouting(Config config) { - Config dbConfig = config.get("db"); - - DbClient dbClient = DbClient.builder(dbConfig) - // add an interceptor to named statement(s) - .addService(DbClientMetrics.counter().statementNames("select-all", "select-one")) - // add an interceptor to statement type(s) - .addService(DbClientMetrics.timer() - .statementTypes(DbStatementType.DELETE, DbStatementType.UPDATE, DbStatementType.INSERT)) - // add an interceptor to all statements - .addService(DbClientTracing.create()) - .build(); - - HealthSupport health = HealthSupport.builder() - .addLiveness( - DbClientHealthCheck.create(dbClient, dbConfig.get("health-check"))) - .build(); - - return Routing.builder() - .register(health) // Health at "/health" - .register(MetricsSupport.create()) // Metrics at "/metrics" - .register("/db", new PokemonService(dbClient)) - .build(); - } - - private static IllegalStateException noConfigError(String key) { - return new IllegalStateException("Attempting to create a Pokemon service with no configuration" - + ", config key: " + key); - } - -} diff --git a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/PokemonService.java b/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/PokemonService.java deleted file mode 100644 index f8f0b0ca32d..00000000000 --- a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/PokemonService.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.dbclient.mongo; - -import io.helidon.dbclient.DbClient; -import io.helidon.examples.dbclient.common.AbstractPokemonService; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT http://localhost:8080/greet/greeting/Hola - * - * The message is returned as a JSON object - */ - -public class PokemonService extends AbstractPokemonService { - - PokemonService(DbClient dbClient) { - super(dbClient); - } - - /** - * Delete all pokemons. - * - * @param request the server request - * @param response the server response - */ - @Override - protected void deleteAllPokemons(ServerRequest request, ServerResponse response) { - dbClient().execute(exec -> exec - .createNamedDelete("delete-all") - .execute()) - .thenAccept(count -> response.send("Deleted: " + count + " values")) - .exceptionally(throwable -> sendError(throwable, response)); - } -} diff --git a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/package-info.java b/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/package-info.java deleted file mode 100644 index 79a3b9e0c07..00000000000 --- a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quick start demo application. - */ -package io.helidon.examples.dbclient.mongo; diff --git a/examples/dbclient/mongodb/src/main/resources/application.yaml b/examples/dbclient/mongodb/src/main/resources/application.yaml deleted file mode 100644 index dc6787a470c..00000000000 --- a/examples/dbclient/mongodb/src/main/resources/application.yaml +++ /dev/null @@ -1,75 +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. -# - -server: - port: 8079 - host: 0.0.0.0 - features: - print-details: true - -# docker run --rm --name mongo -p 27017:27017 mongo -db: - source: "mongoDb" - connection: - url: "mongodb://127.0.0.1:27017/pokemon" - health-check: - type: "query" - statementName: "health-check" - statements: - # Health check statement. HealthCheck statement type must be query. - health-check: '{ - "operation": "command", - "query": { ping: 1 } - }' - # Insert operation contains collection name, operation type and data to be inserted. - # Name variable is stored as MongoDB primary key attribute _id - insert2: '{ - "collection": "pokemons", - "value": { - "_id": $name, - "type": $type - } - }' - select-all: '{ - "collection": "pokemons", - "query": {} - }' - select-one: '{ - "collection": "pokemons", - "query": { - "_id": ? - } - }' - delete-all: '{ - "collection": "pokemons", - "operation": "delete" - }' - update: '{ - "collection": "pokemons", - "query": { - "_id": $name - }, - "value": { - $set: { "type": $type } - } - }' - delete: '{ - "collection": "pokemons", - "query": { - "_id": ? - } - }' - diff --git a/examples/dbclient/mongodb/src/main/resources/logging.properties b/examples/dbclient/mongodb/src/main/resources/logging.properties deleted file mode 100644 index a3b94c39c5f..00000000000 --- a/examples/dbclient/mongodb/src/main/resources/logging.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# Global default logging level. Can be overriden by specific handlers and loggers -.level=INFO - -# Helidon Web Server has a custom log formatter that extends SimpleFormatter. -# It replaces "!thread!" with the current thread name -io.helidon.common.HelidonConsoleHandler.level=ALL -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/dbclient/pokemons/README.md b/examples/dbclient/pokemons/README.md deleted file mode 100644 index 3b8a8c935f6..00000000000 --- a/examples/dbclient/pokemons/README.md +++ /dev/null @@ -1,128 +0,0 @@ -# Helidon DB Client Pokemon Example with JDBC - -This example shows how to run Helidon DB Client over JDBC. - -Application provides REST service endpoint with CRUD operations on Pokemnons -database. - -## Database - -Database model contains two tables: - -**Types** - -| Column | Type | Integrity | -|--------|---------|-------------| -| id | integer | Primary key | -| name | varchar |   | - -**Pokemons** - -| Column | Type | Integrity | -|---------|---------|-------------| -| id | integer | Primary key | -| name | varchar |   | -| id_type | integer | Type(id) | - -with 1:N relationship between *Types* and *Pokemons* - -Examples are given for H2, Oracle, or MySQL databases (note that MySQL is currently not supported for GraalVM native image) - -To switch between JDBC drivers: - -- Uncomment the appropriate dependency in `pom.xml` -- Uncomment the configuration section in `application.yaml` and comment out the current one - -## Build - -To build a jar file -``` -mvn package -``` - -To build a native image (supported only with Oracle, MongoDB, or H2 databases) -``` -mvn package -Pnative-image -``` - -## Database -This example can run with any JDBC supported database. -In the `pom.xml` and `application.yaml` we provide configuration needed for Oracle database, MySQL and H2 database. -Start your database before running this example. - -Example docker commands to start databases in temporary containers: - -Oracle: -``` -docker run --rm --name xe -p 1521:1521 -p 8888:8080 wnameless/oracle-xe-11g-r2 -``` -For details on an Oracle Docker image, see https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance - -H2: -``` -docker run --rm --name h2 -p 9092:9082 -p 8082:8082 nemerosa/h2 -``` -For details, see http://www.h2database.com/html/cheatSheet.html - -MySQL: -``` -docker run --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root \ - -e MYSQL_DATABASE=pokemon -e MYSQL_USER=user -e MYSQL_PASSWORD=password mysql:5.7 -``` - - -## Run - -Then run the `io.helidon.examples.dbclient.pokemons.PokemonMain` class: -``` -java -jar target/helidon-examples-dbclient-pokemons.jar -``` - -Or run the native image: -``` -./target/helidon-examples-dbclient-pokemons -``` - -### Run with MongoDB - -It's possible to run example with MongoDB database. Start it using docker: -``` -docker run --rm --name mongo -p 27017:27017 mongo -``` - -Then run the `io.helidon.examples.dbclient.pokemons.PokemonMain` class with `mongo` argument: -``` -java -jar target/helidon-examples-dbclient-pokemons.jar mongo -``` - -## Test Example - -The application has the following endpoints: - -- http://localhost:8079/db - the main business endpoint (see `curl` commands below) -- http://localhost:8079/metrics - the metrics endpoint (query adds application metrics) -- http://localhost:8079/health - has a custom database health check - -Application also connects to zipkin on default address. -The query operation adds database trace. - -`curl` commands: - -- `curl http://localhost:8079/db/pokemon | json_pp` - list all pokemons in the database -- `curl http://localhost:8079/db/type | json_pp` - list all pokemon types in the database -- `curl http://localhost:8079/db/pokemon/2 | json_pp` - get a single pokemon by id -- `curl http://localhost:8079/db/pokemon/name/Squirtle | json_pp` - get a single pokemon by name -- `curl -i -X POST -d '{"id":7,"name":"Rattata","idType":1}' http://localhost:8079/db/pokemon` - add a new pokemon Rattata -- `curl -i -X PUT -d '{"id":7,"name":"Raticate","idType":2}' http://localhost:8079/db/pokemon` - rename pokemon with id 7 to Raticate -- `curl -i -X DELETE http://localhost:8079/db/pokemon/7` - delete pokemon with id 7 - -### Proxy - -Make sure that `localhost` is not being accessed trough proxy when proxy is configured on your system: -``` -export NO_PROXY='localhost' -``` - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/pokemons/pom.xml b/examples/dbclient/pokemons/pom.xml deleted file mode 100644 index 6ddd126ac48..00000000000 --- a/examples/dbclient/pokemons/pom.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-dbclient-pokemons - Helidon Examples DB Client: Pokemons Database - - - io.helidon.examples.dbclient.pokemons.PokemonMain - jdbc - - - - - io.helidon.health - helidon-health - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing - helidon-tracing-zipkin - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.dbclient - helidon-dbclient-mongodb - - - io.helidon.dbclient - helidon-dbclient-tracing - - - io.helidon.dbclient - helidon-dbclient-metrics - - - io.helidon.dbclient - helidon-dbclient-metrics-jdbc - - - io.helidon.dbclient - helidon-dbclient-health - - - io.helidon.dbclient - helidon-dbclient-jsonp - - - io.helidon.integrations.db - ojdbc - - - - - org.slf4j - slf4j-jdk14 - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.media - helidon-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.metrics - helidon-metrics - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/InitializeDb.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/InitializeDb.java deleted file mode 100644 index 189d221a28b..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/InitializeDb.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.pokemons; - -import io.helidon.common.reactive.Single; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbExecute; - -/** - * Initialize JDBC database schema and populate it with sample data. - */ -public class InitializeDb { - - /** Pokemon types source file. */ - private static final String TYPES = "/Types.json"; - /** Pokemons source file. */ - private static final String POKEMONS = "/Pokemons.json"; - - /** - * Initialize JDBC database schema and populate it with sample data. - * @param dbClient database client - */ - static void init(DbClient dbClient) { - try { - if (!PokemonMain.isMongo()) { - initSchema(dbClient); - } - initData(dbClient); - } catch (Exception ex) { - System.out.printf("Could not initialize database: %s\n", ex.getMessage()); - } - } - - /** - * Initializes database schema (tables). - * - * @param dbClient database client - */ - private static void initSchema(DbClient dbClient) { - try { - dbClient.execute(exec -> exec - .namedDml("create-types") - .flatMapSingle(result -> exec.namedDml("create-pokemons"))) - .await(); - } catch (Exception ex1) { - System.out.printf("Could not create tables: %s", ex1.getMessage()); - try { - deleteData(dbClient); - } catch (Exception ex2) { - System.out.printf("Could not delete tables: %s", ex2.getMessage()); - } - } - } - - /** - * InitializeDb database content (rows in tables). - * - * @param dbClient database client - */ - private static void initData(DbClient dbClient) { - // Init pokemon types - dbClient.execute(exec - -> initTypes(exec) - .flatMapSingle(count -> initPokemons(exec))) - .await(); - } - - /** - * Delete content of all tables. - * - * @param dbClient database client - */ - private static void deleteData(DbClient dbClient) { - dbClient.execute(exec -> exec - .namedDelete("delete-all-pokemons") - .flatMapSingle(count -> exec.namedDelete("delete-all-types"))) - .await(); - } - - /** - * Initialize pokemon types. - * Source data file is JSON file containing array of type objects: - *
-     * [
-     *   { "id": , "name":  },
-     *   ...
-     * ]
-     * 
- * where {@code id} is JSON number and {@ocde name} is JSON String. - * - * @param exec database client executor - * @return executed statements future - */ - private static Single initTypes(DbExecute exec) { - Single stage = Single.just(0L); - try (jakarta.json.JsonReader reader = jakarta.json.Json.createReader(InitializeDb.class.getResourceAsStream(TYPES))) { - jakarta.json.JsonArray types = reader.readArray(); - for (jakarta.json.JsonValue typeValue : types) { - jakarta.json.JsonObject type = typeValue.asJsonObject(); - stage = stage.flatMapSingle(it -> exec.namedInsert( - "insert-type", type.getInt("id"), type.getString("name"))); - } - } - return stage; - } - - /** - * Initialize pokemos. - * Source data file is JSON file containing array of type objects: - *
-     * [
-     *   { "id": , "name": , "type": [, , ...] },
-     *   ...
-     * ]
-     * 
- * where {@code id} is JSON number and {@ocde name} is JSON String. - * - * @param exec database client executor - * @return executed statements future - */ - private static Single initPokemons(DbExecute exec) { - Single stage = Single.just(0L); - try (jakarta.json.JsonReader reader = jakarta.json.Json.createReader(InitializeDb.class.getResourceAsStream(POKEMONS))) { - jakarta.json.JsonArray pokemons = reader.readArray(); - for (jakarta.json.JsonValue pokemonValue : pokemons) { - jakarta.json.JsonObject pokemon = pokemonValue.asJsonObject(); - stage = stage.flatMapSingle(result -> exec - .namedInsert("insert-pokemon", - pokemon.getInt("id"), pokemon.getString("name"), pokemon.getInt("idType"))); - } - } - return stage; - } - - /** - * Creates an instance of database initialization. - */ - private InitializeDb() { - throw new UnsupportedOperationException("Instances of InitializeDb utility class are not allowed"); - } - -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Pokemon.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Pokemon.java deleted file mode 100644 index 1c4a976413b..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Pokemon.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.pokemons; - -import io.helidon.common.Reflected; - -/** - * POJO representing Pokemon. - */ -@Reflected -public class Pokemon { - private int id; - private String name; - private int idType; - - /** - * Default constructor. - */ - public Pokemon() { - // JSON-B - } - - /** - * Create pokemon with name and type. - * - * @param id id of the beast - * @param name name of the beast - * @param idType id of beast type - */ - public Pokemon(int id, String name, int idType) { - this.name = name; - this.idType = idType; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getIdType() { - return idType; - } - - public void setIdType(int idType) { - this.idType = idType; - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMain.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMain.java deleted file mode 100644 index 8289caf110f..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMain.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.dbclient.pokemons; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.health.HealthSupport; -import io.helidon.media.jsonb.JsonbSupport; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Simple Hello World rest application. - */ -public final class PokemonMain { - - /** MongoDB configuration. Default configuration file {@code appliaction.yaml} contains JDBC configuration. */ - private static final String MONGO_CFG = "mongo.yaml"; - - /** Whether MongoDB support is selected. */ - private static boolean mongo; - - static boolean isMongo() { - return mongo; - } - - /** - * Cannot be instantiated. - */ - private PokemonMain() { - } - - /** - * Application main entry point. - * - * @param args Command line arguments. Run with MongoDB support when 1st argument is mongo, run with JDBC support otherwise. - */ - public static void main(final String[] args) { - if (args != null && args.length > 0 && args[0] != null && "mongo".equals(args[0].toLowerCase())) { - System.out.println("MongoDB database selected"); - mongo = true; - } else { - System.out.println("JDBC database selected"); - mongo = false; - } - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link io.helidon.webserver.WebServer} instance - */ - static WebServer startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = isMongo() ? Config.create(ConfigSources.classpath(MONGO_CFG)) : Config.create(); - - // Prepare routing for the server - Routing routing = createRouting(config); - - WebServer server = WebServer.builder(routing) - .addMediaSupport(JsonpSupport.create()) - .addMediaSupport(JsonbSupport.create()) - .config(config.get("server")) - .tracer(TracerBuilder.create(config.get("tracing")).build()) - .build(); - - // Start the server and print some info. - server.start() - .thenAccept(ws -> System.out.println("WEB server is up! http://localhost:" + ws.port() + "/")); - - // Server threads are not daemon. NO need to block. Just react. - server.whenShutdown() - .thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - - return server; - } - - /** - * Creates new {@link io.helidon.webserver.Routing}. - * - * @param config configuration of this server - * @return routing configured with JSON support, a health check, and a service - */ - private static Routing createRouting(Config config) { - Config dbConfig = config.get("db"); - - // Client services are added through a service loader - see mongoDB example for explicit services - DbClient dbClient = DbClient.builder(dbConfig) - .build(); - // Some relational databases do not support DML statement as ping so using query which works for all of them - HealthSupport health = HealthSupport.builder() - .addLiveness( - DbClientHealthCheck.create(dbClient, dbConfig.get("health-check"))) - .build(); - - // Initialize database schema - InitializeDb.init(dbClient); - - return Routing.builder() - .register(health) // Health at "/health" - .register(MetricsSupport.create()) // Metrics at "/metrics" - .register("/db", new PokemonService(dbClient)) - .build(); - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapper.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapper.java deleted file mode 100644 index 22a308aaf34..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapper.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.pokemons; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbColumn; -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -/** - * Maps database statements to {@link io.helidon.examples.dbclient.common.Pokemon} class. - */ -public class PokemonMapper implements DbMapper { - - @Override - public Pokemon read(DbRow row) { - DbColumn id = row.column("id"); - DbColumn name = row.column("name"); - DbColumn type = row.column("idType"); - return new Pokemon(id.as(Integer.class), name.as(String.class), type.as(Integer.class)); - } - - @Override - public Map toNamedParameters(Pokemon value) { - Map map = new HashMap<>(3); - map.put("id", value.getId()); - map.put("name", value.getName()); - map.put("idType", value.getIdType()); - return map; - } - - @Override - public List toIndexedParameters(Pokemon value) { - List list = new ArrayList<>(3); - list.add(value.getId()); - list.add(value.getName()); - list.add(value.getIdType()); - return list; - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapperProvider.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapperProvider.java deleted file mode 100644 index 359835f008d..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapperProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.dbclient.pokemons; - -import java.util.Optional; - -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.spi.DbMapperProvider; - -import jakarta.annotation.Priority; - -/** - * Provides pokemon mappers. - */ -@Priority(1000) -public class PokemonMapperProvider implements DbMapperProvider { - private static final PokemonMapper MAPPER = new PokemonMapper(); - - @SuppressWarnings("unchecked") - @Override - public Optional> mapper(Class type) { - if (type.equals(Pokemon.class)) { - return Optional.of((DbMapper) MAPPER); - } - return Optional.empty(); - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonService.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonService.java deleted file mode 100644 index 7f4ad00aa5f..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonService.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.dbclient.pokemons; - -import java.util.concurrent.CompletionException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.webserver.Handler; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.JsonObject; - -/** - * Example service using a database. - */ -public class PokemonService implements Service { - - private static final Logger LOGGER = Logger.getLogger(PokemonService.class.getName()); - - private final DbClient dbClient; - - PokemonService(DbClient dbClient) { - this.dbClient = dbClient; - } - - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::index) - // List all types - .get("/type", this::listTypes) - // List all pokemons - .get("/pokemon", this::listPokemons) - // Get pokemon by name - .get("/pokemon/name/{name}", this::getPokemonByName) - // Get pokemon by ID - .get("/pokemon/{id}", this::getPokemonById) - // Create new pokemon - .post("/pokemon", Handler.create(Pokemon.class, this::insertPokemon)) - // Update name of existing pokemon - .put("/pokemon", Handler.create(Pokemon.class, this::updatePokemon)) - // Delete pokemon by ID including type relation - .delete("/pokemon/{id}", this::deletePokemonById); - } - - - /** - * Return index page. - * - * @param request the server request - * @param response the server response - */ - private void index(ServerRequest request, ServerResponse response) { - response.headers().contentType(MediaType.TEXT_PLAIN); - response.send(""" - Pokemon JDBC Example: - GET /type - List all pokemon types - GET /pokemon - List all pokemons - GET /pokemon/{id} - Get pokemon by id - GET /pokemon/name/{name} - Get pokemon by name - POST /pokemon - Insert new pokemon: - {"id":,"name":,"type":} - PUT /pokemon - Update pokemon - {"id":,"name":,"type":} - DELETE /pokemon/{id} - Delete pokemon with specified id - """); - } - - /** - * Return JsonArray with all stored pokemons. - * Pokemon object contains list of all type names. - * This method is abstract because implementation is DB dependent. - * - * @param request the server request - * @param response the server response - */ - private void listTypes(ServerRequest request, ServerResponse response) { - response.send(dbClient.execute(exec -> exec.namedQuery("select-all-types")) - .map(it -> it.as(JsonObject.class)), JsonObject.class); - } - - /** - * Return JsonArray with all stored pokemons. - * Pokemon object contains list of all type names. - * This method is abstract because implementation is DB dependent. - * - * @param request the server request - * @param response the server response - */ - private void listPokemons(ServerRequest request, ServerResponse response) { - response.send(dbClient.execute(exec -> exec.namedQuery("select-all-pokemons")) - .map(it -> it.as(JsonObject.class)), JsonObject.class); - } - - /** - * Get a single pokemon by id. - * - * @param request server request - * @param response server response - */ - private void getPokemonById(ServerRequest request, ServerResponse response) { - try { - int pokemonId = Integer.parseInt(request.path().param("id")); - dbClient.execute(exec -> exec - .createNamedGet("select-pokemon-by-id") - .addParam("id", pokemonId) - .execute()) - .thenAccept(maybeRow -> maybeRow - .ifPresentOrElse( - row -> sendRow(row, response), - () -> sendNotFound(response, "Pokemon " + pokemonId + " not found"))) - .exceptionally(throwable -> sendError(throwable, response)); - } catch (NumberFormatException ex) { - sendError(ex, response); - } - } - - /** - * Get a single pokemon by name. - * - * @param request server request - * @param response server response - */ - private void getPokemonByName(ServerRequest request, ServerResponse response) { - String pokemonName = request.path().param("name"); - dbClient.execute(exec -> exec.namedGet("select-pokemon-by-name", pokemonName)) - .thenAccept(it -> { - if (it.isEmpty()) { - sendNotFound(response, "Pokemon " + pokemonName + " not found"); - } else { - sendRow(it.get(), response); - } - }) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Insert new pokemon with specified name. - * - * @param request the server request - * @param response the server response - */ - private void insertPokemon(ServerRequest request, ServerResponse response, Pokemon pokemon) { - dbClient.execute(exec -> exec - .createNamedInsert("insert-pokemon") - .indexedParam(pokemon) - .execute()) - .thenAccept(count -> response.send("Inserted: " + count + " values\n")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Update a pokemon. - * Uses a transaction. - * - * @param request the server request - * @param response the server response - */ - private void updatePokemon(ServerRequest request, ServerResponse response, Pokemon pokemon) { - dbClient.execute(exec -> exec - .createNamedUpdate("update-pokemon-by-id") - .namedParam(pokemon) - .execute()) - .thenAccept(count -> response.send("Updated: " + count + " values\n")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Delete pokemon with specified id (key). - * - * @param request the server request - * @param response the server response - */ - private void deletePokemonById(ServerRequest request, ServerResponse response) { - try { - int id = Integer.parseInt(request.path().param("id")); - dbClient.execute(exec -> exec - .createNamedDelete("delete-pokemon-by-id") - .addParam("id", id) - .execute()) - .thenAccept(count -> response.send("Deleted: " + count + " values\n")) - .exceptionally(throwable -> sendError(throwable, response)); - } catch (NumberFormatException ex) { - sendError(ex, response); - } - } - - /** - * Delete pokemon with specified id (key). - * - * @param request the server request - * @param response the server response - */ - private void deleteAllPokemons(ServerRequest request, ServerResponse response) { - // Response message contains information about deleted records from both tables - StringBuilder sb = new StringBuilder(); - // Pokemon must be removed from both PokemonTypes and Pokemons tables in transaction - dbClient.execute(exec -> exec - // Execute delete from PokemonTypes table - .createDelete("DELETE FROM Pokemons") - .execute()) - // Process response when transaction is completed - .thenAccept(count -> response.send("Deleted: " + count + " values\n")) - .exceptionally(throwable -> sendError(throwable, response)); - } - - /** - * Send a 404 status code. - * - * @param response the server response - * @param message entity content - */ - private void sendNotFound(ServerResponse response, String message) { - response.status(Http.Status.NOT_FOUND_404); - response.send(message); - } - - /** - * Send a single DB row as JSON object. - * - * @param row row as read from the database - * @param response server response - */ - private void sendRow(DbRow row, ServerResponse response) { - response.send(row.as(jakarta.json.JsonObject.class)); - } - - /** - * Send a 500 response code and a few details. - * - * @param throwable throwable that caused the issue - * @param response server response - * @param type of expected response, will be always {@code null} - * @return {@code Void} so this method can be registered as a lambda - * with {@link java.util.concurrent.CompletionStage#exceptionally(java.util.function.Function)} - */ - private T sendError(Throwable throwable, ServerResponse response) { - Throwable realCause = throwable; - if (throwable instanceof CompletionException) { - realCause = throwable.getCause(); - } - response.status(Http.Status.INTERNAL_SERVER_ERROR_500); - response.send("Failed to process request: " + realCause.getClass().getName() + "(" + realCause.getMessage() + ")"); - LOGGER.log(Level.WARNING, "Failed to process request", throwable); - return null; - } - -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/package-info.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/package-info.java deleted file mode 100644 index 4ddeaee4d58..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quick start demo application. - */ -package io.helidon.examples.dbclient.pokemons; diff --git a/examples/dbclient/pokemons/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider b/examples/dbclient/pokemons/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider deleted file mode 100644 index 1d19c17ca87..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -io.helidon.examples.dbclient.pokemons.PokemonMapperProvider diff --git a/examples/dbclient/pokemons/src/main/resources/Pokemons.json b/examples/dbclient/pokemons/src/main/resources/Pokemons.json deleted file mode 100644 index c4e78bed732..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/Pokemons.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - {"id": 1, "name": "Bulbasaur", "idType": 12}, - {"id": 2, "name": "Charmander", "idType": 10}, - {"id": 3, "name": "Squirtle", "idType": 11}, - {"id": 4, "name": "Caterpie", "idType": 7}, - {"id": 5, "name": "Weedle", "idType": 7}, - {"id": 6, "name": "Pidgey", "idType": 3} -] diff --git a/examples/dbclient/pokemons/src/main/resources/Types.json b/examples/dbclient/pokemons/src/main/resources/Types.json deleted file mode 100644 index 646ec725b82..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/Types.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - {"id": 1, "name": "Normal"}, - {"id": 2, "name": "Fighting"}, - {"id": 3, "name": "Flying"}, - {"id": 4, "name": "Poison"}, - {"id": 5, "name": "Ground"}, - {"id": 6, "name": "Rock"}, - {"id": 7, "name": "Bug"}, - {"id": 8, "name": "Ghost"}, - {"id": 9, "name": "Steel"}, - {"id": 10, "name": "Fire"}, - {"id": 11, "name": "Water"}, - {"id": 12, "name": "Grass"}, - {"id": 13, "name": "Electric"}, - {"id": 14, "name": "Psychic"}, - {"id": 15, "name": "Ice"}, - {"id": 16, "name": "Dragon"}, - {"id": 17, "name": "Dark"}, - {"id": 18, "name": "Fairy"} -] diff --git a/examples/dbclient/pokemons/src/main/resources/application.yaml b/examples/dbclient/pokemons/src/main/resources/application.yaml deleted file mode 100644 index ed1ead16586..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/application.yaml +++ /dev/null @@ -1,92 +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. -# - -server: - port: 8079 - host: 0.0.0.0 - features: - print-details: true - -tracing: - service: jdbc-db - -# see README.md for details how to run databases in docker -db: - source: jdbc - connection: - # - # Oracle configuration - # - url: "jdbc:oracle:thin:@localhost:1521/XE" - username: "system" - password: "oracle" - poolName: "oracle" - # - # MySQL configuration - # -# url: jdbc:mysql://127.0.0.1:3306/pokemon?useSSL=false -# username: user -# password: password -# poolName: "mysql" - # - # H2 configuration - # -# url: "jdbc:h2:tcp://localhost:9092/~test" -# username: h2 -# password: "${EMPTY}" -# poolName: h2 - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - services: - tracing: - - enabled: true - metrics: - - type: METER - health-check: - type: "query" - statementName: "health-check" - statements: - # Health check query statement for MySQL and H2 databases -# health-check: "SELECT 0" - # Health check query statement for Oracle database - health-check: "SELECT 1 FROM DUAL" - ## Create database schema (table "Types" is system in H2) - create-types: "CREATE TABLE PokeTypes (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL, id_type INTEGER NOT NULL REFERENCES PokeTypes(id))" - # Select all types - select-all-types: "SELECT id, name FROM PokeTypes" - # Select all pokemons without type information - select-all-pokemons: "SELECT id, name, id_type FROM Pokemons" - # Select pokemon by id - select-pokemon-by-id: "SELECT id, name, id_type FROM Pokemons WHERE id = :id" - # Select pokemon by name - select-pokemon-by-name: "SELECT id, name, id_type FROM Pokemons WHERE name = ?" - # Insert records into database - insert-type: "INSERT INTO PokeTypes(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name, id_type) VALUES(?, ?, ?)" - # Update name of pokemon specified by id - update-pokemon-by-id: "UPDATE Pokemons SET name = :name, id_type = :idType WHERE id = :id" - # Delete pokemon by id - delete-pokemon-by-id: "DELETE FROM Pokemons WHERE id = :id" - # Delete all types - delete-all-types: "DELETE FROM PokeTypes" - # Delete all pokemons - delete-all-pokemons: "DELETE FROM Pokemons" diff --git a/examples/dbclient/pokemons/src/main/resources/logging.properties b/examples/dbclient/pokemons/src/main/resources/logging.properties deleted file mode 100644 index a3b94c39c5f..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/logging.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# Global default logging level. Can be overriden by specific handlers and loggers -.level=INFO - -# Helidon Web Server has a custom log formatter that extends SimpleFormatter. -# It replaces "!thread!" with the current thread name -io.helidon.common.HelidonConsoleHandler.level=ALL -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/dbclient/pokemons/src/main/resources/mongo.yaml b/examples/dbclient/pokemons/src/main/resources/mongo.yaml deleted file mode 100644 index 854c7a52426..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/mongo.yaml +++ /dev/null @@ -1,114 +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. -# - -server: - port: 8079 - host: 0.0.0.0 - features: - print-details: true - -tracing: - service: mongo-db - -# docker run --rm --name mongo -p 27017:27017 mongo -db: - source: "mongoDb" - connection: - url: "mongodb://127.0.0.1:27017/pokemon" - services: - tracing: - - enabled: true - metrics: - - type: METER - statements: - # Health check statement. HealthCheck statement type must be query. - health-check: '{ - "operation": "command", - "query": { ping: 1 } - }' - ## Create database schema - # Select all types - select-all-types: '{ - "collection": "types", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": {} - }' - # Select all pokemons without type information - select-all-pokemons: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": {} - }' - # Select pokemon by id - select-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": { id: $id } - }' - # Select pokemon by name - select-pokemon-by-name: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": { name: ? } - }' - # Insert records into database - insert-type: '{ - "collection": "types", - "operation": "insert", - "value": { - "id": ?, - "name": ? - } - }' - insert-pokemon: '{ - "collection": "pokemons", - "operation": "insert", - "value": { - "id": ?, - "name": ?, - "id_type": ? - } - }' - # Update name of pokemon specified by id - update-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "update", - "value":{ $set: { "name": $name, "id_type": $idType } }, - "query": { id: $id } - }' - # Delete pokemon by id - delete-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "delete", - "query": { id: $id } - }' - # Delete all types - delete-all-types: '{ - "collection": "types", - "operation": "delete", - "query": { } - }' - # Delete all pokemons - delete-all-pokemons: '{ - "collection": "pokemons", - "operation": "delete", - "query": { } - }' - diff --git a/examples/dbclient/pom.xml b/examples/dbclient/pom.xml deleted file mode 100644 index 07b9b6c7c04..00000000000 --- a/examples/dbclient/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - - pom - - io.helidon.examples.dbclient - helidon-examples-dbclient-project - Helidon Examples DB Client - - - Examples of Helidon DB Client - - - - - jdbc - mongodb - common - pokemons - - diff --git a/examples/employee-app/.dockerignore b/examples/employee-app/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/employee-app/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/employee-app/Dockerfile b/examples/employee-app/Dockerfile deleted file mode 100644 index 29b4c387002..00000000000 --- a/examples/employee-app/Dockerfile +++ /dev/null @@ -1,45 +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. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-employee-app.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-examples-employee-app.jar"] - -EXPOSE 8080 diff --git a/examples/employee-app/README.md b/examples/employee-app/README.md deleted file mode 100644 index 25f8aeaa603..00000000000 --- a/examples/employee-app/README.md +++ /dev/null @@ -1,293 +0,0 @@ -# Helidon Quickstart SE - Employee Directory Example - -This project implements an employee directory REST service using Helidon SE. - The application is composed of a Helidon REST Microservice backend along with - an HTML/JavaScript front end. The source for both application is included with - the Maven project. - -By default the service uses a ArrayList backend with sample data. You can connect - the backend application to an Oracle database by changing the values in the - `resources/application.yaml` file. - -The service uses Helidon DB Client that provides reactive and non-blocking access to a database. - -## Build and run - -```bash -mvn package -java -jar target/employee-app.jar -``` - -## Create script -If you do not have the employee table in your database, you can create it and required resources as follows: - -```sql -CREATE TABLE EMPLOYEE (ID NUMBER(6), - FIRSTNAME VARCHAR2(20), - LASTNAME VARCHAR2(25), - EMAIL VARCHAR2(30), - PHONE VARCHAR2(30), - BIRTHDATE VARCHAR2(15), - TITLE VARCHAR2(20), - DEPARTMENT VARCHAR2(20)); - -ALTER TABLE EMPLOYEE ADD (CONSTRAINT emp_id_pk PRIMARY KEY (ID)); - -CREATE SEQUENCE EMPLOYEE_SEQ INCREMENT BY 1 NOCACHE NOCYCLE; -``` - -## Exercise the application -Get all employees. -```sh -curl -X GET curl -X GET http://localhost:8080/employees -``` - -Only 1 output record is shown for brevity: -```json -[ - { - "birthDate": "1970-11-28T08:28:48.078Z", - "department": "Mobility", - "email": "Hugh.Jast@example.com", - "firstName": "Hugh", - "id": "48cf06ad-6ed4-47e6-ac44-3ea9c67cbe2d", - "lastName": "Jast", - "phone": "730-715-4446", - "title": "National Data Strategist" - } -] -``` - - -Get all employees whose last name contains "S". -```sh -curl -X GET http://localhost:8080/employees/lastname/S -``` - -Only 1 output record is shown for brevity: -```json -[ - { - "birthDate": "1978-03-18T17:00:12.938Z", - "department": "Security", - "email": "Zora.Sawayn@example.com", - "firstName": "Zora", - "id": "d7b583a2-f068-40d9-aec0-6f87899c5d8a", - "lastName": "Sawayn", - "phone": "923-814-0502", - "title": "Dynamic Marketing Designer" - } -] -``` - -Get an individual record. -```sh -curl -X GET http://localhost:8080/employees/48cf06ad-6ed4-47e6-ac44-3ea9c67cbe2d -``` -Output: -```json -[ - { - "birthDate": "1970-11-28T08:28:48.078Z", - "department": "Mobility", - "email": "Hugh.Jast@example.com", - "firstName": "Hugh", - "id": "48cf06ad-6ed4-47e6-ac44-3ea9c67cbe2d", - "lastName": "Jast", - "phone": "730-715-4446", - "title": "National Data Strategist" - } -] -``` - -Connect with a web brower at: -```txt -http://localhost:8080/public/index.html -``` - - -## Try health and metrics - -```sh -curl -s -X GET http://localhost:8080/health -``` - -```json -{ - "outcome": "UP", - "checks": [ - { - "name": "deadlock", - "state": "UP" - }, - { - "name": "diskSpace", - "state": "UP", - "data": { - "free": "306.61 GB", - "freeBytes": 329225338880, - "percentFree": "65.84%", - "total": "465.72 GB", - "totalBytes": 500068036608 - } - }, - { - "name": "heapMemory", - "state": "UP", - "data": { - "free": "239.35 MB", - "freeBytes": 250980656, - "max": "4.00 GB", - "maxBytes": 4294967296, - "percentFree": "99.59%", - "total": "256.00 MB", - "totalBytes": 268435456 - } - } - ] -} -``` - -### Prometheus Format - -```sh -curl -s -X GET http://localhost:8080/metrics -``` - -Only 1 output item is shown for brevity: -```txt -# TYPE base:classloader_current_loaded_class_count counter -# HELP base:classloader_current_loaded_class_count Displays the number of classes that are currently loaded in the Java virtual machine. -base:classloader_current_loaded_class_count 3995 -``` - -### JSON Format -```sh -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -``` - -Output: -```json -{ - "base": { - "classloader.currentLoadedClass.count": 4011, - "classloader.totalLoadedClass.count": 4011, - "classloader.totalUnloadedClass.count": 0, - "cpu.availableProcessors": 8, - "cpu.systemLoadAverage": 1.65283203125, - "gc.G1 Old Generation.count": 0, - "gc.G1 Old Generation.time": 0, - "gc.G1 Young Generation.count": 2, - "gc.G1 Young Generation.time": 8, - "jvm.uptime": 478733, - "memory.committedHeap": 268435456, - "memory.maxHeap": 4294967296, - "memory.usedHeap": 18874368, - "thread.count": 11, - "thread.daemon.count": 4, - "thread.max.count": 11 - }, - "vendor": { - "grpc.requests.count": 0, - "grpc.requests.meter": { - "count": 0, - "meanRate": 0, - "oneMinRate": 0, - "fiveMinRate": 0, - "fifteenMinRate": 0 - }, - "requests.count": 5, - "requests.meter": { - "count": 5, - "meanRate": 0.01046407983617782, - "oneMinRate": 0.0023897243038835964, - "fiveMinRate": 0.003944597070306631, - "fifteenMinRate": 0.0023808575122958794 - } - } -} -``` - -## Build the Docker Image - -```sh -docker build -t employee-app . -``` - -## Start the application with Docker - -```sh -docker run --rm -p 8080:8080 employee-app:latest -``` - -Exercise the application as described above. - -## Deploy the application to Kubernetes - -```txt -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deply application -kubectl get service employee-app # Get service info -``` - - -### Oracle DB Credentials -You can connect to two different datastores for the back end application. - Just fill in the application.yaml files. To use an ArrayList as the data store, - simply set `drivertype` to `Array`. To connect to an Oracle database, you must - set all the values: `user`, `password`, `hosturl`, and `drivertype`. - For Oracle, the `drivertype` should be set to `Oracle`. - -**Sample `application.yaml`** -```yaml -app: - user: - password: - hosturl: :/. - drivertype: Array - - server: - port: 8080 - host: 0.0.0.0 -``` - -## Create the database objects - -1. Create a connection to your Oracle Database using sqlplus or SQL Developer. - See https://docs.cloud.oracle.com/iaas/Content/Database/Tasks/connectingDB.htm. -2. Create the database objects: - -```sql -CREATE TABLE EMPLOYEE ( - ID INTEGER NOT NULL, - FIRSTNAME VARCHAR(100), - LASTNAME VARCHAR(100), - EMAIL VARCHAR(100), - PHONE VARCHAR(100), - BIRTHDATE VARCHAR(10), - TITLE VARCHAR(100), - DEPARTMENT VARCHAR(100), - PRIMARY KEY (ID) - ); -``` - -```sql -CREATE SEQUENCE EMPLOYEE_SEQ - START WITH 100 - INCREMENT BY 1; -``` - -```sql -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Hugh', 'Jast', 'Hugh.Jast@example.com', '730-555-0100', '1970-11-28', 'National Data Strategist', 'Mobility'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Toy', 'Herzog', 'Toy.Herzog@example.com', '769-555-0102', '1961-08-08', 'Dynamic Operations Manager', 'Paradigm'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Reed', 'Hahn', 'Reed.Hahn@example.com', '429-555-0153', '1977-02-05', 'Future Directives Facilitator', 'Quality'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Novella', 'Bahringer', 'Novella.Bahringer@example.com', '293-596-3547', '1961-07-25', 'Principal Factors Architect', 'Division'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Zora', 'Sawayn', 'Zora.Sawayn@example.com', '923-555-0161', '1978-03-18', 'Dynamic Marketing Designer', 'Security'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Cordia', 'Willms', 'Cordia.Willms@example.com', '778-555-0187', '1989-03-31', 'Human Division Representative', 'Optimization'); -``` diff --git a/examples/employee-app/app.yaml b/examples/employee-app/app.yaml deleted file mode 100644 index 0d0a40ceaaa..00000000000 --- a/examples/employee-app/app.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-examples-employee-app - labels: - app: helidon-examples-employee-app -spec: - type: NodePort - selector: - app: helidon-examples-employee-app - ports: - - port: 8080 - targetPort: 8080 - name: http ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-examples-employee-app -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-employee-app - version: v1 - spec: - containers: - - name: helidon-examples-employee-app - image: helidon-examples-employee-app - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 ---- -apiVersion: v1 -kind: Service -metadata: - name: helidon-examples-employee-app - labels: - app: helidon-examples-employee-app -spec: - type: LoadBalancer - ports: - - port: 80 - targetPort: 8080 - selector: - app: helidon-examples-employee-app \ No newline at end of file diff --git a/examples/employee-app/pom.xml b/examples/employee-app/pom.xml deleted file mode 100644 index 38a0bf180f9..00000000000 --- a/examples/employee-app/pom.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../applications/se/pom.xml - - io.helidon.examples.employee - helidon-examples-employee-app - Helidon Examples Employee App - - - io.helidon.service.employee.Main - - - - - io.helidon.integrations.db - ojdbc - - - com.oracle.database.jdbc - ucp - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.media - helidon-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.dbclient - helidon-dbclient - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.metrics - helidon-metrics - runtime - - - io.helidon.webclient - helidon-webclient - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/employee-app/src/main/java/io/helidon/service/employee/Employee.java b/examples/employee-app/src/main/java/io/helidon/service/employee/Employee.java deleted file mode 100644 index 8f3a09eb7e9..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/service/employee/Employee.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.service.employee; - -import java.util.UUID; - -import jakarta.json.bind.annotation.JsonbCreator; -import jakarta.json.bind.annotation.JsonbProperty; -/** - * Represents an employee. - */ -public final class Employee { - - private final String id; - private final String firstName; - private final String lastName; - private final String email; - private final String phone; - private final String birthDate; - private final String title; - private final String department; - - /**Creates a new Employee. - * @param id The employee ID. - * @param firstName The employee first name. - * @param lastName The employee lastName. - * @param email The employee email. - * @param phone The employee phone. - * @param birthDate The employee birthDatee. - * @param title The employee title. - * @param department The employee department.*/ - @SuppressWarnings("checkstyle:ParameterNumber") - private Employee(String id, String firstName, String lastName, String email, String phone, String birthDate, - String title, String department) { - this.id = id; - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - this.phone = phone; - this.birthDate = birthDate; - this.title = title; - this.department = department; - } - - /** - * Creates a new employee. This method helps to parse the json parameters in the requests. - * @param id The employee ID. If the employee ID is null or empty generates a new ID. - * @param firstName The employee first name. - * @param lastName The employee lastName. - * @param email The employee email. - * @param phone The employee phone. - * @param birthDate The employee birthDatee. - * @param title The employee title. - * @param department The employee department. - * @return A new employee object - */ - @JsonbCreator - @SuppressWarnings("checkstyle:ParameterNumber") - public static Employee of(@JsonbProperty("id") String id, @JsonbProperty("firstName") String firstName, - @JsonbProperty("lastName") String lastName, @JsonbProperty("email") String email, - @JsonbProperty("phone") String phone, @JsonbProperty("birthDate") String birthDate, - @JsonbProperty("title") String title, @JsonbProperty("department") String department) { - if (id == null || id.trim().equals("")) { - id = UUID.randomUUID().toString(); - } - Employee e = new Employee(id, firstName, lastName, email, phone, birthDate, title, department); - return e; - } - - /** - * Returns the employee ID. - * @return the ID - */ - public String getId() { - return this.id; - } - - /** - * Returns the employee first name. - * @return The first name - */ - public String getFirstName() { - return this.firstName; - } - - /** - * Returns the employee last name. - * @return The last name - */ - public String getLastName() { - return this.lastName; - } - - /** - * Returns the employee e-mail. - * @return The email - */ - public String getEmail() { - return this.email; - } - - /** - * Returns the employee phone. - * @return The phone - */ - public String getPhone() { - return this.phone; - } - - /** - * Returns the employee birthdate. - * @return The birthdate - */ - public String getBirthDate() { - return this.birthDate; - } - - /** - * Returns the employee title. - * @return The title - */ - public String getTitle() { - return this.title; - } - - /** - * Returns the employee department. - * @return The department - */ - public String getDepartment() { - return this.department; - } - - @Override - public String toString() { - return "ID: " + id + " First Name: " + firstName + " Last Name: " + lastName + " EMail: " + email + " Phone: " - + phone + " Birth Date: " + birthDate + " Title: " + title + " Department: " + department; - } - -} diff --git a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepository.java b/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepository.java deleted file mode 100644 index 020ff5b6b7a..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepository.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.service.employee; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletionStage; - -import io.helidon.config.Config; - -/** - * Interface for Data Access Objects. - *

- * As Helidon SE is a reactive framework, we cannot block it. - * Method on this interface return a {@link java.util.concurrent.CompletionStage} with the data, so it - * can be correctly handled by the server. - *

- * Methods in implementation must not block thread - */ -public interface EmployeeRepository { - - /** - * Create a new employeeRepository instance using one of the two implementations - * {@link EmployeeRepositoryImpl} or {@link EmployeeRepositoryImplDB} depending - * on the specified driver type. - * @param driverType Represents the driver type. It can be Array or Oracle. - * @param config Contains the application configuration specified in the - * application.yaml file. - * @return The employee repository implementation. - */ - static EmployeeRepository create(String driverType, Config config) { - switch (driverType) { - case "Database": - return new EmployeeRepositoryImplDB(config); - case "Array": - default: - // Array is default - return new EmployeeRepositoryImpl(); - } - } - - /** - * Returns the list of the employees. - * @return The collection of all the employee objects - */ - CompletionStage> getAll(); - - /** - * Returns the list of the employees that match with the specified lastName. - * @param lastName Represents the last name value for the search. - * @return The collection of the employee objects that match with the specified - * lastName - */ - CompletionStage> getByLastName(String lastName); - - /** - * Returns the list of the employees that match with the specified title. - * @param title Represents the title value for the search - * @return The collection of the employee objects that match with the specified - * title - */ - CompletionStage> getByTitle(String title); - - /** - * Returns the list of the employees that match with the specified department. - * @param department Represents the department value for the search. - * @return The collection of the employee objects that match with the specified - * department - */ - CompletionStage> getByDepartment(String department); - - /** - * Add a new employee. - * @param employee returns the employee object including the ID generated. - * @return the employee object including the ID generated - */ - CompletionStage save(Employee employee); // Add new employee - - /** - * Update an existing employee. - * @param updatedEmployee The employee object with the values to update - * @param id The employee ID - * @return number of updated records - */ - CompletionStage update(Employee updatedEmployee, String id); - - /** - * Delete an employee by ID. - * @param id The employee ID - * @return number of deleted records - */ - CompletionStage deleteById(String id); - - /** - * Get an employee by ID. - * @param id The employee ID - * @return The employee object if the employee is found - */ - CompletionStage> getById(String id); -} diff --git a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImpl.java b/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImpl.java deleted file mode 100644 index 613ff323360..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImpl.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.service.employee; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.stream.Collectors; - -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; -import jakarta.json.bind.JsonbConfig; - -/** - * Implementation of the {@link EmployeeRepository}. This implementation uses a - * mock database written with in-memory ArrayList classes. - * The strings id, name, and other search strings are validated before being - * passed to the methods in this class. - * - */ -public final class EmployeeRepositoryImpl implements EmployeeRepository { - - private final CopyOnWriteArrayList eList = new CopyOnWriteArrayList(); - - /** - * To load the initial data, parses the content of employee.json - * file located in the resources directory to a list of Employee - * objects. - */ - public EmployeeRepositoryImpl() { - JsonbConfig config = new JsonbConfig().withFormatting(Boolean.TRUE); - - Jsonb jsonb = JsonbBuilder.create(config); - try (InputStream jsonFile = EmployeeRepositoryImpl.class.getResourceAsStream("/employees.json")) { - Employee[] employees = jsonb.fromJson(jsonFile, Employee[].class); - eList.addAll(Arrays.asList(employees)); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Override - public CompletionStage> getByLastName(String name) { - List matchList = eList.stream().filter((e) -> (e.getLastName().contains(name))) - .collect(Collectors.toList()); - - return CompletableFuture.completedFuture(matchList); - } - - @Override - public CompletionStage> getByTitle(String title) { - List matchList = eList.stream().filter((e) -> (e.getTitle().contains(title))) - .collect(Collectors.toList()); - - return CompletableFuture.completedFuture(matchList); - } - - @Override - public CompletableFuture> getByDepartment(String department) { - List matchList = eList.stream().filter((e) -> (e.getDepartment().contains(department))) - .collect(Collectors.toList()); - - return CompletableFuture.completedFuture(matchList); - } - - @Override - public CompletionStage> getAll() { - return CompletableFuture.completedFuture(eList); - } - - @Override - public CompletionStage> getById(String id) { - return CompletableFuture.completedFuture(eList.stream().filter(e -> e.getId().equals(id)).findFirst()); - } - - @Override - public CompletionStage save(Employee employee) { - Employee nextEmployee = Employee.of(null, - employee.getFirstName(), - employee.getLastName(), - employee.getEmail(), - employee.getPhone(), - employee.getBirthDate(), - employee.getTitle(), - employee.getDepartment()); - eList.add(nextEmployee); - return CompletableFuture.completedFuture(nextEmployee); - } - - @Override - public CompletionStage update(Employee updatedEmployee, String id) { - deleteById(id); - Employee e = Employee.of(id, updatedEmployee.getFirstName(), updatedEmployee.getLastName(), - updatedEmployee.getEmail(), updatedEmployee.getPhone(), updatedEmployee.getBirthDate(), - updatedEmployee.getTitle(), updatedEmployee.getDepartment()); - eList.add(e); - return CompletableFuture.completedFuture(1L); - } - - @Override - public CompletionStage deleteById(String id) { - return CompletableFuture.completedFuture(eList.stream() - .filter(e -> e.getId().equals(id)) - .findFirst() - .map(eList::remove) - .map(it -> 1L) - .orElse(0L)); - } -} diff --git a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImplDB.java b/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImplDB.java deleted file mode 100644 index ca1b6537c9c..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeRepositoryImplDB.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.service.employee; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletionStage; - -import io.helidon.common.reactive.Multi; -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.dbclient.jdbc.JdbcDbClientProviderBuilder; - -/** - * Implementation of the {@link EmployeeRepository}. This implementation uses an - * Oracle database to persist the Employee objects. - * - */ -final class EmployeeRepositoryImplDB implements EmployeeRepository { - - private final DbClient dbClient; - - /** - * Creates the database connection using the parameters specified in the - * application.yaml file located in the resources directory. - * @param config Represents the application configuration. - */ - EmployeeRepositoryImplDB(Config config) { - String url = "jdbc:oracle:thin:@"; - String driver = "oracle.jdbc.driver.OracleDriver"; - - String dbUserName = config.get("app.user").asString().orElse("sys as SYSDBA"); - String dbUserPassword = config.get("app.password").asString().orElse("password"); - String dbHostURL = config.get("app.hosturl").asString().orElse("localhost:1521/xe"); - - try { - Class.forName(driver); - } catch (Exception sqle) { - sqle.printStackTrace(); - } - - // now we create the reactive DB Client - explicitly use JDBC, so we can - // configure JDBC specific configuration - dbClient = JdbcDbClientProviderBuilder.create() - .url(url + dbHostURL) - .username(dbUserName) - .password(dbUserPassword) - .build(); - } - - @Override - public CompletionStage> getAll() { - String queryStr = "SELECT * FROM EMPLOYEE"; - - return toEmployeeList(dbClient.execute(exec -> exec.query(queryStr))); - } - - @Override - public CompletionStage> getByLastName(String name) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE LASTNAME LIKE ?"; - - return toEmployeeList(dbClient.execute(exec -> exec.query(queryStr, name))); - } - - @Override - public CompletionStage> getByTitle(String title) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE TITLE LIKE ?"; - - return toEmployeeList(dbClient.execute(exec -> exec.query(queryStr, title))); - } - - @Override - public CompletionStage> getByDepartment(String department) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE DEPARTMENT LIKE ?"; - - return toEmployeeList(dbClient.execute(exec -> exec.query(queryStr, department))); - } - - @Override - public CompletionStage save(Employee employee) { - String insertTableSQL = "INSERT INTO EMPLOYEE " - + "(ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) " - + "VALUES(EMPLOYEE_SEQ.NEXTVAL,?,?,?,?,?,?,?)"; - - return dbClient.execute(exec -> exec.createInsert(insertTableSQL) - .addParam(employee.getFirstName()) - .addParam(employee.getLastName()) - .addParam(employee.getEmail()) - .addParam(employee.getPhone()) - .addParam(employee.getBirthDate()) - .addParam(employee.getTitle()) - .addParam(employee.getDepartment()) - .execute()) - // let's always return the employee once the insert finishes - .thenApply(count -> employee); - } - - @Override - public CompletionStage deleteById(String id) { - String deleteRowSQL = "DELETE FROM EMPLOYEE WHERE ID=?"; - - return dbClient.execute(exec -> exec.delete(deleteRowSQL, id)); - } - - @Override - public CompletionStage> getById(String id) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE ID =?"; - - return dbClient.execute(exec -> exec.get(queryStr, id)) - .map(optionalRow -> optionalRow.map(dbRow -> dbRow.as(Employee.class))); - } - - @Override - public CompletionStage update(Employee updatedEmployee, String id) { - String updateTableSQL = "UPDATE EMPLOYEE SET FIRSTNAME=?, LASTNAME=?, EMAIL=?, PHONE=?, BIRTHDATE=?, TITLE=?, " - + "DEPARTMENT=? WHERE ID=?"; - - return dbClient.execute(exec -> exec.createUpdate(updateTableSQL) - .addParam(updatedEmployee.getFirstName()) - .addParam(updatedEmployee.getLastName()) - .addParam(updatedEmployee.getEmail()) - .addParam(updatedEmployee.getPhone()) - .addParam(updatedEmployee.getBirthDate()) - .addParam(updatedEmployee.getTitle()) - .addParam(updatedEmployee.getDepartment()) - .addParam(Integer.parseInt(id)) - .execute()); - } - - private static CompletionStage> toEmployeeList(Multi resultSet) { - return resultSet.map(EmployeeDbMapper::read) - .collectList(); - } - - private static final class EmployeeDbMapper { - private EmployeeDbMapper() { - } - - static Employee read(DbRow row) { - // map named columns to an object - return Employee.of( - row.column("ID").as(String.class), - row.column("FIRSTNAME").as(String.class), - row.column("LASTNAME").as(String.class), - row.column("EMAIL").as(String.class), - row.column("PHONE").as(String.class), - row.column("BIRTHDATE").as(String.class), - row.column("TITLE").as(String.class), - row.column("DEPARTMENT").as(String.class) - ); - } - } -} diff --git a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeService.java b/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeService.java deleted file mode 100644 index cb54d7f63c1..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/service/employee/EmployeeService.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.service.employee; - -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * The Employee service endpoints. Get all employees: curl -X GET - * http://localhost:8080/employees Get employee by id: curl -X GET - * http://localhost:8080/employees/{id} Add employee curl -X POST - * http://localhost:8080/employees/{id} Update employee by id curl -X PUT - * http://localhost:8080/employees/{id} Delete employee by id curl -X DELETE - * http://localhost:8080/employees/{id} The message is returned as a JSON object - */ -public class EmployeeService implements Service { - private final EmployeeRepository employees; - private static final Logger LOGGER = Logger.getLogger(EmployeeService.class.getName()); - - EmployeeService(Config config) { - employees = EmployeeRepository.create(config.get("app.drivertype") - .asString() - .orElse("Array"), - config); - } - - /** - * A service registers itself by updating the routine rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules.get("/", this::getAll) - .get("/lastname/{name}", this::getByLastName) - .get("/department/{name}", this::getByDepartment) - .get("/title/{name}", this::getByTitle) - .post("/", this::save) - .get("/{id}", this::getEmployeeById) - .put("/{id}", this::update) - .delete("/{id}", this::delete); - } - - /** - * Gets all the employees. - * @param request the server request - * @param response the server response - */ - private void getAll(final ServerRequest request, final ServerResponse response) { - LOGGER.fine("getAll"); - - this.employees - .getAll() - .thenAccept(response::send) - .exceptionally(response::send); - } - - /** - * Gets the employees by the last name specified in the parameter. - * @param request the server request - * @param response the server response - */ - private void getByLastName(final ServerRequest request, final ServerResponse response) { - LOGGER.fine("getByLastName"); - - String name = request.path().param("name"); - // Invalid query strings handled in isValidQueryStr. Keeping DRY - if (isValidQueryStr(response, name)) { - this.employees.getByLastName(name) - .thenAccept(response::send) - .exceptionally(response::send); - } - } - - /** - * Gets the employees by the title specified in the parameter. - * @param request the server request - * @param response the server response - */ - private void getByTitle(final ServerRequest request, final ServerResponse response) { - LOGGER.fine("getByTitle"); - - String title = request.path().param("name"); - if (isValidQueryStr(response, title)) { - this.employees.getByTitle(title) - .thenAccept(response::send) - .exceptionally(response::send); - } - } - - /** - * Gets the employees by the department specified in the parameter. - * @param request the server request - * @param response the server response - */ - private void getByDepartment(final ServerRequest request, final ServerResponse response) { - LOGGER.fine("getByDepartment"); - - String department = request.path().param("name"); - if (isValidQueryStr(response, department)) { - this.employees.getByDepartment(department) - .thenAccept(response::send) - .exceptionally(response::send); - } - } - - /** - * Gets the employees by the ID specified in the parameter. - * @param request the server request - * @param response the server response - */ - private void getEmployeeById(ServerRequest request, ServerResponse response) { - LOGGER.fine("getEmployeeById"); - - String id = request.path().param("id"); - // If invalid, response handled in isValidId. Keeping DRY - if (isValidQueryStr(response, id)) { - this.employees.getById(id) - .thenAccept(it -> { - if (it.isPresent()) { - // found - response.send(it.get()); - } else { - // not found - response.status(404).send(); - } - }) - .exceptionally(response::send); - } - } - - /** - * Saves a new employee. - * @param request the server request - * @param response the server response - */ - private void save(ServerRequest request, ServerResponse response) { - LOGGER.fine("save"); - - request.content() - .as(Employee.class) - .thenApply(e -> Employee.of(null, - e.getFirstName(), - e.getLastName(), - e.getEmail(), - e.getPhone(), - e.getBirthDate(), - e.getTitle(), - e.getDepartment())) - .thenCompose(this.employees::save) - .thenAccept(it -> response.status(201).send()) - .exceptionally(response::send); - } - - /** - * Updates an existing employee. - * @param request the server request - * @param response the server response - */ - private void update(ServerRequest request, ServerResponse response) { - LOGGER.fine("update"); - - String id = request.path().param("id"); - - if (isValidQueryStr(response, id)) { - request.content() - .as(Employee.class) - .thenCompose(e -> this.employees.update(e, id)) - .thenAccept(count -> { - if (count == 0) { - response.status(404).send(); - } else { - response.status(204).send(); - } - }) - .exceptionally(response::send); - - } - - } - - /** - * Deletes an existing employee. - * @param request the server request - * @param response the server response - */ - private void delete(final ServerRequest request, final ServerResponse response) { - LOGGER.fine("delete"); - - String id = request.path().param("id"); - - if (isValidQueryStr(response, id)) { - this.employees.deleteById(id) - .thenAccept(count -> { - if (count == 0) { - response.status(404).send(); - } else { - response.status(204).send(); - } - }) - .exceptionally(response::send); - } - } - - /** - * Validates the parameter. - * @param response the server response - * @param nameStr - * @return - */ - private boolean isValidQueryStr(ServerResponse response, String nameStr) { - Map errorMessage = new HashMap<>(); - if (nameStr == null || nameStr.isEmpty() || nameStr.length() > 100) { - errorMessage.put("errorMessage", "Invalid query string"); - response.status(400).send(errorMessage); - return false; - } else { - return true; - } - } -} diff --git a/examples/employee-app/src/main/java/io/helidon/service/employee/Main.java b/examples/employee-app/src/main/java/io/helidon/service/employee/Main.java deleted file mode 100644 index 73102b28a91..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/service/employee/Main.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.service.employee; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonb.JsonbSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -/** - * Simple Employee rest application. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // Get webserver config from the "server" section of application.yaml and JSON support registration - Single server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonbSupport.create()) - .build() - .start(); - - server.thenAccept(ws -> { - System.out.println("WEB server is up!"); - System.out.println("Web client at: http://localhost:" + ws.port() - + "/public/index.html"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }).exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - // Server threads are not daemon. No need to block. Just react. - - return server; - } - - /** - * Creates new {@link Routing}. - * - * @param config configuration of this server - * @return routing configured with a health check, and a service - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - EmployeeService employeeService = new EmployeeService(config); - HealthSupport health = HealthSupport.builder().addLiveness(HealthChecks.healthChecks()) - .build(); // Adds a convenient set of checks - - return Routing.builder() - .register("/public", StaticContentSupport.builder("public") - .welcomeFileName("index.html")) - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register("/employees", employeeService) - .build(); - } - -} diff --git a/examples/employee-app/src/main/java/io/helidon/service/employee/package-info.java b/examples/employee-app/src/main/java/io/helidon/service/employee/package-info.java deleted file mode 100644 index addc5ad6ce2..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/service/employee/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Employee example application - *

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

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

Cloud Employee App

- - -
-
-
LOADING...
-
-
- - - - diff --git a/examples/employee-app/src/main/resources/public/nopic.png b/examples/employee-app/src/main/resources/public/nopic.png deleted file mode 100644 index 5967653cf93f2cb98fcad0eb9cf66be3bdd558dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3584 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 diff --git a/examples/employee-app/src/test/java/io/helidon/service/employee/MainTest.java b/examples/employee-app/src/test/java/io/helidon/service/employee/MainTest.java deleted file mode 100644 index f4572a8d070..00000000000 --- a/examples/employee-app/src/test/java/io/helidon/service/employee/MainTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.service.employee; - -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - - @BeforeAll - public static void startTheServer() { - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addHeader(Http.Header.ACCEPT, MediaType.APPLICATION_JSON.toString()) - .build(); - } - - @AfterAll - public static void stopServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - @Test - public void testHelloWorld() { - webClient.get() - .path("/employees") - .request() - .thenAccept(response -> { - response.close(); - assertThat("HTTP response2", response.status(), is(Http.Status.OK_200)); - }) - .await(); - - webClient.get() - .path("/health") - .request() - .thenAccept(response -> { - response.close(); - assertThat("HTTP response2", response.status(), is(Http.Status.OK_200)); - }) - .await(); - - webClient.get() - .path("/metrics") - .request() - .thenAccept(response -> { - response.close(); - assertThat("HTTP response2", response.status(), is(Http.Status.OK_200)); - }) - .await(); - } - -} diff --git a/examples/graphql/basics/README.md b/examples/graphql/basics/README.md deleted file mode 100644 index 3e39e8d945b..00000000000 --- a/examples/graphql/basics/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Helidon GraphQL Basic Example - -This example shows the basics of using Helidon SE GraphQL. The example -manually creates a GraphQL Schema using the [GraphQL Java](https://github.com/graphql-java/graphql-java) API. - -## Build and run - -Start the application: - -```bash -mvn package -java -jar target/helidon-examples-graphql-basics.jar -``` - -Note the port number reported by the application. - -Probe the GraphQL endpoints: - -1. Hello word endpoint: - - ```bash - curl -X POST http://127.0.0.1:PORT/graphql -d '{"query":"query { hello }"}' - - "data":{"hello":"world"}} - ``` - -1. Hello in different languages - - ```bash - curl -X POST http://127.0.0.1:PORT/graphql -d '{"query":"query { helloInDifferentLanguages }"}' - - {"data":{"helloInDifferentLanguages":["Bonjour","Hola","Zdravstvuyte","Nǐn hǎo","Salve","Gudday","Konnichiwa","Guten Tag"]}} - ``` diff --git a/examples/graphql/basics/pom.xml b/examples/graphql/basics/pom.xml deleted file mode 100644 index 3b757dddc25..00000000000 --- a/examples/graphql/basics/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.graphql - helidon-examples-graphql-basics - Helidon GraphQL Examples Basics - - - Basic usage of GraphQL in helidon SE - - - - io.helidon.examples.graphql.basics.Main - - - - - io.helidon.graphql - helidon-graphql-server - - - io.helidon.webserver - helidon-webserver - - - io.helidon.common - helidon-common - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/Main.java b/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/Main.java deleted file mode 100644 index 124d704fda9..00000000000 --- a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/Main.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.graphql.basics; - -import java.util.List; - -import io.helidon.graphql.server.GraphQlSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import graphql.schema.DataFetcher; -import graphql.schema.GraphQLSchema; -import graphql.schema.StaticDataFetcher; -import graphql.schema.idl.RuntimeWiring; -import graphql.schema.idl.SchemaGenerator; -import graphql.schema.idl.SchemaParser; -import graphql.schema.idl.TypeDefinitionRegistry; - -/** - * Main class of Graphql SE integration example. - */ -public class Main { - - private Main() { - } - - /** - * Start the example. Prints endpoints to standard output. - * - * @param args not used - */ - public static void main(String[] args) { - WebServer server = WebServer.builder() - .routing(Routing.builder() - .register(GraphQlSupport.create(buildSchema())) - .build()) - .build(); - - server.start() - .thenApply(webServer -> { - String endpoint = "http://localhost:" + webServer.port(); - System.out.println("GraphQL started on " + endpoint + "/graphql"); - System.out.println("GraphQL schema available on " + endpoint + "/graphql/schema.graphql"); - return null; - }); - } - - /** - * Generate a {@link GraphQLSchema}. - * @return a {@link GraphQLSchema} - */ - private static GraphQLSchema buildSchema() { - String schema = "type Query{\n" - + "hello: String \n" - + "helloInDifferentLanguages: [String] \n" - + "\n}"; - - SchemaParser schemaParser = new SchemaParser(); - TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema); - - // DataFetcher to return various hello's in difference languages - DataFetcher> hellosDataFetcher = (DataFetcher>) environment -> - List.of("Bonjour", "Hola", "Zdravstvuyte", "Nǐn hǎo", "Salve", "Gudday", "Konnichiwa", "Guten Tag"); - - RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring() - .type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("world"))) - .type("Query", builder -> builder.dataFetcher("helloInDifferentLanguages", hellosDataFetcher)) - .build(); - - SchemaGenerator schemaGenerator = new SchemaGenerator(); - return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring); - } -} diff --git a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/package-info.java b/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/package-info.java deleted file mode 100644 index a0f3c7ceb07..00000000000 --- a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Example of healthchecks in helidon SE. - */ -package io.helidon.examples.graphql.basics; diff --git a/examples/graphql/pom.xml b/examples/graphql/pom.xml deleted file mode 100644 index 9a256471e27..00000000000 --- a/examples/graphql/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - 4.0.0 - - helidon-examples-project - io.helidon.examples - 3.2.7-SNAPSHOT - - io.helidon.examples.graphql - helidon-examples-graphql-project - pom - Helidon GraphQL Examples - - - basics - - diff --git a/examples/grpc/.dockerignore b/examples/grpc/.dockerignore deleted file mode 100644 index 901b6e6f9c6..00000000000 --- a/examples/grpc/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -*/target/ diff --git a/examples/grpc/README.md b/examples/grpc/README.md deleted file mode 100644 index 70fd1bfd615..00000000000 --- a/examples/grpc/README.md +++ /dev/null @@ -1 +0,0 @@ -# Helidon MP and SE gRPC Server Examples diff --git a/examples/grpc/basics/README.md b/examples/grpc/basics/README.md deleted file mode 100644 index b8ad4b84cf3..00000000000 --- a/examples/grpc/basics/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Helidon gRPC Example - -A basic example gRPC server. - -## Build and run - -```bash -mvn -f ../pom.xml -pl common,basics package -java -jar target/helidon-examples-grpc-basics.jar -``` - -Exercise the example: -```bash -java -cp target/helidon-examples-grpc-basics.jar \ - io.helidon.grpc.examples.basics.HealthClient -``` - -The HealthClient will give this output: -```bash -GreetService response -> status: SERVING - -FooService StatusRuntimeException.getMessage() -> NOT_FOUND: Service 'FooService' does not exist or does not have a registered health check - -``` diff --git a/examples/grpc/basics/pom.xml b/examples/grpc/basics/pom.xml deleted file mode 100644 index 425c9ec27f2..00000000000 --- a/examples/grpc/basics/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-basics - Helidon gRPC Server Examples Basics - - - Examples of elementary use of the gRPC Server - - - - io.helidon.grpc.examples.basics.Server - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.grpc - helidon-grpc-server - - - io.helidon.grpc - helidon-grpc-client - - - io.helidon.health - helidon-health-checks - - - io.helidon.bundles - helidon-bundles-config - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/HealthClient.java b/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/HealthClient.java deleted file mode 100644 index e241bc78242..00000000000 --- a/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/HealthClient.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.basics; - -import io.helidon.grpc.client.ClientServiceDescriptor; -import io.helidon.grpc.client.GrpcServiceClient; - -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.StatusRuntimeException; -import io.grpc.health.v1.HealthCheckRequest; -import io.grpc.health.v1.HealthCheckResponse; -import io.grpc.health.v1.HealthGrpc; - -/** - * A gRPC health check client implemented with Helidon gRPC client API. - *

- * This example uses the java-grpc built in health check client. - */ -public class HealthClient { - - private HealthClient() { - } - - /** - * The program entry point. - * - * @param args the program arguments - */ - public static void main(String[] args) { - ClientServiceDescriptor descriptor = ClientServiceDescriptor - .builder(HealthGrpc.getServiceDescriptor()) - .build(); - - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - GrpcServiceClient grpcClient = GrpcServiceClient.create(channel, descriptor); - - // query the health of a deployed service - HealthCheckResponse response = grpcClient.blockingUnary("Check", - HealthCheckRequest.newBuilder().setService("GreetService").build()); - - System.out.println("GreetService response -> " + response); - - // query the health of a non-existent service - try { - grpcClient.blockingUnary("Check", - HealthCheckRequest.newBuilder().setService("FooService").build()); - } catch (StatusRuntimeException e) { - // expect to catch a NOT_FOUND exception - System.out.println("FooService StatusRuntimeException.getMessage() -> " + e.getMessage()); - } - } -} diff --git a/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/Server.java b/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/Server.java deleted file mode 100644 index cb8b0cd6cdb..00000000000 --- a/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/Server.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.basics; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.GreetService; -import io.helidon.grpc.examples.common.GreetServiceJava; -import io.helidon.grpc.examples.common.StringService; -import io.helidon.grpc.server.GrpcRouting; -import io.helidon.grpc.server.GrpcServer; -import io.helidon.grpc.server.GrpcServerConfiguration; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * A basic example of a Helidon gRPC server. - */ -public class Server { - - private Server() { - } - - /** - * The main program entry point. - * - * @param args the program arguments - */ - public static void main(String[] args) { - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // load logging configuration - LogConfig.configureRuntime(); - - // Get gRPC server config from the "grpc" section of application.yaml - GrpcServerConfiguration serverConfig = - GrpcServerConfiguration.builder(config.get("grpc")).build(); - - GrpcServer grpcServer = GrpcServer.create(serverConfig, createRouting(config)); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - grpcServer.start() - .thenAccept(s -> { - System.out.println("gRPC server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - // add support for standard and gRPC health checks - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) - .addLiveness(grpcServer.healthChecks()) - .build(); - - // start web server with health endpoint - Routing routing = Routing.builder() - .register(health) - .build(); - - WebServer.create(routing, config.get("webserver")) - .start() - .thenAccept(s -> { - System.out.println("HTTP server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("HTTP server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - } - - private static GrpcRouting createRouting(Config config) { - GreetService greetService = new GreetService(config); - GreetServiceJava greetServiceJava = new GreetServiceJava(config); - - return GrpcRouting.builder() - .register(greetService) - .register(greetServiceJava) - .register(new StringService()) - .build(); - } -} diff --git a/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/package-info.java b/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/package-info.java deleted file mode 100644 index 42d37360741..00000000000 --- a/examples/grpc/basics/src/main/java/io/helidon/grpc/examples/basics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A set of small usage examples. Start with {@link io.helidon.grpc.examples.basics.Server Main} class. - */ -package io.helidon.grpc.examples.basics; diff --git a/examples/grpc/basics/src/main/resources/application.yaml b/examples/grpc/basics/src/main/resources/application.yaml deleted file mode 100644 index 5a1485a38f4..00000000000 --- a/examples/grpc/basics/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# 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. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -grpc: - name: "test.server" - port: 1408 - -webserver: - port: 8080 - bind-address: "0.0.0.0" diff --git a/examples/grpc/basics/src/main/resources/logging.properties b/examples/grpc/basics/src/main/resources/logging.properties deleted file mode 100644 index f9dfd25b9da..00000000000 --- a/examples/grpc/basics/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/grpc/client-standalone/README.md b/examples/grpc/client-standalone/README.md deleted file mode 100644 index 09c90c68f42..00000000000 --- a/examples/grpc/client-standalone/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Helidon gRPC Standalone client - -An example gRPC client. Can be used with the [basics](../basics/README.md) example that would act as a server. - -This example is created to test native image on pure client side, so it does not have a server side -implemented. - -## Build and run - -```bash -mvn -f ../pom.xml -pl common,client-standalone package -java -jar target/helidon-examples-grpc-client-standalone.jar -``` - -The client invokes the string service on the server, and should print out: -``` -Text 'lower case original' to upper case is 'LOWER CASE ORIGINAL' -``` diff --git a/examples/grpc/client-standalone/pom.xml b/examples/grpc/client-standalone/pom.xml deleted file mode 100644 index 7136ebf4114..00000000000 --- a/examples/grpc/client-standalone/pom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-client-standalone - Helidon gRPC Server Examples Standalone client - - - A standalone client invoking a strings gRPC service (such as in basics example) - - - - io.helidon.grpc.examples.client.standalone.StandaloneClient - - - - - io.helidon.grpc - helidon-grpc-core - - - io.helidon.grpc - helidon-grpc-client - - - io.grpc - grpc-netty - - - io.grpc - grpc-services - - - io.grpc - grpc-protobuf - - - - javax.annotation - javax.annotation-api - provided - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - - - - compile - compile-custom - - - - - - - diff --git a/examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/StandaloneClient.java b/examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/StandaloneClient.java deleted file mode 100644 index 3ddc88698bd..00000000000 --- a/examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/StandaloneClient.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.client.standalone; - -import io.helidon.grpc.examples.common.StringServiceGrpc; -import io.helidon.grpc.examples.common.Strings; - -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; - -/** - * A gRPC client using only client side libraries. - * To test it, please setup a server, such as the one in "basics" example of Helidon grpc examples. - */ -public class StandaloneClient { - private StandaloneClient() { - } - - /** - * Start the client with a single invocation to the server. - * - * @param args ignored - */ - public static void main(String[] args) { - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - StringServiceGrpc.StringServiceBlockingStub stub = StringServiceGrpc.newBlockingStub(channel); - - String text = "lower case original"; - Strings.StringMessage request = Strings.StringMessage.newBuilder().setText(text).build(); - Strings.StringMessage response = stub.upper(request); - - System.out.println("Text '" + text + "' to upper case is '" + response.getText() + "'"); - } -} diff --git a/examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/package-info.java b/examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/package-info.java deleted file mode 100644 index 7269b5ac891..00000000000 --- a/examples/grpc/client-standalone/src/main/java/io/helidon/grpc/examples/client/standalone/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Standalone gRPC client example. - */ -package io.helidon.grpc.examples.client.standalone; diff --git a/examples/grpc/client-standalone/src/main/proto/strings.proto b/examples/grpc/client-standalone/src/main/proto/strings.proto deleted file mode 100644 index 437a75ace7f..00000000000 --- a/examples/grpc/client-standalone/src/main/proto/strings.proto +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -syntax = "proto3"; -option java_package = "io.helidon.grpc.examples.common"; - -service StringService { - rpc Upper (StringMessage) returns (StringMessage) {} - rpc Lower (StringMessage) returns (StringMessage) {} - rpc Split (StringMessage) returns (stream StringMessage) {} - rpc Join (stream StringMessage) returns (StringMessage) {} - rpc Echo (stream StringMessage) returns (stream StringMessage) {} -} - -message StringMessage { - string text = 1; -} diff --git a/examples/grpc/client-standalone/src/main/resources/logging.properties b/examples/grpc/client-standalone/src/main/resources/logging.properties deleted file mode 100644 index fe4a22c9607..00000000000 --- a/examples/grpc/client-standalone/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -.level=INFO diff --git a/examples/grpc/common/README.md b/examples/grpc/common/README.md deleted file mode 100644 index 1ac7eb2d84b..00000000000 --- a/examples/grpc/common/README.md +++ /dev/null @@ -1 +0,0 @@ -# Helidon gRPC Examples Common Library diff --git a/examples/grpc/common/pom.xml b/examples/grpc/common/pom.xml deleted file mode 100644 index c06b53b8063..00000000000 --- a/examples/grpc/common/pom.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-common - Helidon gRPC Server Examples ProtoBuf Services - - - ProtoBuf generated gRPC services used in gRPC examples - - - - io.helidon.grpc.examples.common.GreetClient - - - - - io.helidon.grpc - helidon-grpc-server - - - io.helidon.grpc - helidon-grpc-client - - - io.grpc - grpc-netty - - - io.grpc - grpc-services - - - io.grpc - grpc-protobuf - - - io.helidon.common - helidon-common - - - io.helidon.media - helidon-media-jsonb - - - - javax.annotation - javax.annotation-api - true - - - - - - - kr.motd.maven - os-maven-plugin - - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - - - - compile - compile-custom - - - - - - - diff --git a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/EchoService.java b/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/EchoService.java deleted file mode 100644 index 6bea4bd92aa..00000000000 --- a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/EchoService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.common; - - -import io.grpc.stub.StreamObserver; - -/** - * An implementation of the protocol buffer generated EchoService. - */ -public class EchoService - extends EchoServiceGrpc.EchoServiceImplBase { - - @Override - public void echo(Echo.EchoRequest request, StreamObserver observer) { - observer.onNext(Echo.EchoResponse.newBuilder().setMessage(request.getMessage()).build()); - observer.onCompleted(); - } -} diff --git a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetClient.java b/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetClient.java deleted file mode 100644 index 115995c3b3c..00000000000 --- a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetClient.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.common; - -import java.net.URI; - -import io.helidon.grpc.client.ClientRequestAttribute; -import io.helidon.grpc.client.ClientServiceDescriptor; -import io.helidon.grpc.client.ClientTracingInterceptor; -import io.helidon.grpc.client.GrpcServiceClient; -import io.helidon.grpc.examples.common.Greet.GreetRequest; -import io.helidon.grpc.examples.common.Greet.GreetResponse; -import io.helidon.grpc.examples.common.Greet.SetGreetingRequest; -import io.helidon.grpc.examples.common.Greet.SetGreetingResponse; -import io.helidon.tracing.Tracer; -import io.helidon.tracing.TracerBuilder; - -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; - -/** - * A client for the {@link GreetService} implemented with Helidon gRPC client API. - */ -public class GreetClient { - - private GreetClient() { - } - - /** - * The program entry point. - * - * @param args the program arguments - */ - public static void main(String[] args) { - Tracer tracer = TracerBuilder.create("Client") - .collectorUri(URI.create("http://localhost:9411/api/v2/spans")) - .build(); - - ClientTracingInterceptor tracingInterceptor = ClientTracingInterceptor.builder(tracer) - .withVerbosity() - .withTracedAttributes(ClientRequestAttribute.ALL_CALL_OPTIONS) - .build(); - - ClientServiceDescriptor descriptor = ClientServiceDescriptor - .builder(GreetServiceGrpc.getServiceDescriptor()) - .intercept(tracingInterceptor) - .build(); - - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - GrpcServiceClient client = GrpcServiceClient.create(channel, descriptor); - - // Obtain a greeting from the GreetService - GreetRequest request = GreetRequest.newBuilder().setName("Aleks").build(); - GreetResponse firstGreeting = client.blockingUnary("Greet", request); - System.out.println("First greeting: '" + firstGreeting.getMessage() + "'"); - - // Change the greeting - SetGreetingRequest setRequest = SetGreetingRequest.newBuilder().setGreeting("Ciao").build(); - SetGreetingResponse setResponse = client.blockingUnary("SetGreeting", setRequest); - System.out.println("Greeting set to: '" + setResponse.getGreeting() + "'"); - - // Obtain a second greeting from the GreetService - GreetResponse secondGreeting = client.blockingUnary("Greet", request); - System.out.println("Second greeting: '" + secondGreeting.getMessage() + "'"); - } -} diff --git a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetService.java b/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetService.java deleted file mode 100644 index 1c103435b34..00000000000 --- a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetService.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.common; - -import java.util.Optional; - -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.Greet.GreetRequest; -import io.helidon.grpc.examples.common.Greet.GreetResponse; -import io.helidon.grpc.examples.common.Greet.SetGreetingRequest; -import io.helidon.grpc.examples.common.Greet.SetGreetingResponse; -import io.helidon.grpc.server.GrpcService; -import io.helidon.grpc.server.ServiceDescriptor; - -import io.grpc.stub.StreamObserver; -import org.eclipse.microprofile.health.HealthCheckResponse; - -import static io.helidon.grpc.core.ResponseHelper.complete; - -/** - * A plain Java implementation of the GreetService. - */ -public class GreetService implements GrpcService { - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - /** - * Create a {@link GreetService}. - * - * @param config the service configuration - */ - public GreetService(Config config) { - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - } - - @Override - public void update(ServiceDescriptor.Rules rules) { - rules.proto(Greet.getDescriptor()) - .unary("Greet", this::greet) - .unary("SetGreeting", this::setGreeting) - .healthCheck(this::healthCheck); - } - - // ---- service methods ------------------------------------------------- - - private void greet(GreetRequest request, StreamObserver observer) { - String name = Optional.ofNullable(request.getName()).orElse("World"); - String msg = String.format("%s %s!", greeting, name); - - complete(observer, GreetResponse.newBuilder().setMessage(msg).build()); - } - - private void setGreeting(SetGreetingRequest request, StreamObserver observer) { - greeting = request.getGreeting(); - - complete(observer, SetGreetingResponse.newBuilder().setGreeting(greeting).build()); - } - - private HealthCheckResponse healthCheck() { - return HealthCheckResponse - .named(name()) - .up() - .withData("time", System.currentTimeMillis()) - .withData("greeting", greeting) - .build(); - } -} diff --git a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetServiceJava.java b/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetServiceJava.java deleted file mode 100644 index da447bf8f0d..00000000000 --- a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/GreetServiceJava.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.common; - -import java.util.Optional; - -import io.helidon.config.Config; -import io.helidon.grpc.core.JsonbMarshaller; -import io.helidon.grpc.server.GrpcService; -import io.helidon.grpc.server.ServiceDescriptor; - -import io.grpc.stub.StreamObserver; - -import static io.helidon.grpc.core.ResponseHelper.complete; - -/** - * A plain Java implementation of the GreetService. - */ -public class GreetServiceJava - implements GrpcService { - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - /** - * Create a {@link GreetServiceJava}. - * - * @param config the service configuration - */ - public GreetServiceJava(Config config) { - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - } - - @Override - public void update(ServiceDescriptor.Rules rules) { - rules.marshallerSupplier(new JsonbMarshaller.Supplier()) - .unary("Greet", this::greet) - .unary("SetGreeting", this::setGreeting); - } - - // ---- service methods ------------------------------------------------- - - private void greet(String name, StreamObserver observer) { - name = Optional.ofNullable(name).orElse("World"); - String msg = String.format("%s %s!", greeting, name); - - complete(observer, msg); - } - - private void setGreeting(String greeting, StreamObserver observer) { - this.greeting = greeting; - - complete(observer, greeting); - } -} diff --git a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringClient.java b/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringClient.java deleted file mode 100644 index c18b26492c0..00000000000 --- a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringClient.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.common; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.stream.Collectors; - -import io.helidon.grpc.client.ClientServiceDescriptor; -import io.helidon.grpc.client.GrpcServiceClient; -import io.helidon.grpc.examples.common.Strings.StringMessage; - -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.stub.StreamObserver; - -/** - * A client to the {@link StringService} implemented with Helidon gRPC client API. - */ -public class StringClient { - private static String inputStr = "Test_String_for_Lower_and_Upper"; - private static StringMessage inputMsg = StringMessage.newBuilder().setText(inputStr).build(); - - private StringClient() { - } - - /** - * Program entry point. - * - * @param args the program arguments - * - * @throws Exception if an error occurs - */ - public static void main(String[] args) throws Exception { - ClientServiceDescriptor descriptor = ClientServiceDescriptor - .builder(StringServiceGrpc.getServiceDescriptor()) - .build(); - - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - GrpcServiceClient client = GrpcServiceClient.create(channel, descriptor); - - unary(client); - asyncUnary(client); - blockingUnary(client); - clientStreaming(client); - clientStreamingOfIterable(client); - serverStreamingBlocking(client); - serverStreaming(client); - bidirectional(client); - } - - /** - * Call the unary {@code Lower} method using an normal unary call. - * - * @param client the StringService {@link GrpcServiceClient} - * @throws java.lang.Exception if the call fails - */ - public static void unary(GrpcServiceClient client) throws Exception { - FutureObserver observer = new FutureObserver(); - client.unary("Lower", inputMsg, observer); - - String response = observer.get(); - - System.out.println("Unary Lower response: '" + response + "'"); - } - - /** - * Call the unary {@code Lower} method using an async call. - * - * @param client the StringService {@link GrpcServiceClient} - */ - public static void asyncUnary(GrpcServiceClient client) { - CompletionStage stage = client.unary("Lower", inputMsg); - - stage.handle((response, error) -> { - if (error == null) { - System.out.println("Async Lower response: '" + response.getText() + "'"); - } else { - error.printStackTrace(); - } - return null; - }); - } - - /** - * Call the unary {@code Upper} method using a blocking call. - * - * @param client the StringService {@link GrpcServiceClient} - */ - public static void blockingUnary(GrpcServiceClient client) { - StringMessage upperResonse = client.blockingUnary("Upper", inputMsg); - - System.out.println("Blocking Upper response: '" + upperResonse.getText() + "'"); - } - - /** - * Call the client streaming {@code Join} method. - * - * @param client the StringService {@link GrpcServiceClient} - * @throws java.lang.Exception if the call fails - */ - public static void clientStreaming(GrpcServiceClient client) throws Exception { - FutureObserver responses = new FutureObserver(); - StreamObserver requests = client.clientStreaming("Join", responses); - - List joinValues = List.of("A", "B", "C", "D"); - - // stream the values to the server - joinValues.forEach(word -> requests.onNext(StringMessage.newBuilder().setText(word).build())); - requests.onCompleted(); - - // wait for the response observer to complete - String joined = responses.get(); - - System.out.println("Join response: '" + joined + "'"); - } - - /** - * Call the client streaming {@code Join} method streaming the contents of an {@link Iterable}. - * - * @param client the StringService {@link GrpcServiceClient} - * @throws java.lang.Exception if the call fails - */ - public static void clientStreamingOfIterable(GrpcServiceClient client) throws Exception { - List joinValues = List.of("A", "B", "C", "D") - .stream() - .map(val -> StringMessage.newBuilder().setText(val).build()) - .collect(Collectors.toList()); - - // stream the value to the server - CompletionStage stage = client.clientStreaming("Join", joinValues); - - // wait for the response future to complete - stage.handle((response, error) -> { - if (error == null) { - System.out.println("Join response: '" + response.getText() + "'"); - } else { - error.printStackTrace(); - } - return null; - }); - } - - /** - * Call the server streaming {@code Split} method using a blocking call. - * - * @param client the StringService {@link GrpcServiceClient} - */ - public static void serverStreamingBlocking(GrpcServiceClient client) { - String stringToSplit = "A B C D E"; - StringMessage request = StringMessage.newBuilder().setText(stringToSplit).build(); - - Iterator iterator = client.blockingServerStreaming("Split", request); - - while (iterator.hasNext()) { - StringMessage response = iterator.next(); - System.out.println("Response from blocking Split: '" + response.getText() + "'"); - } - } - - /** - * Call the server streaming {@code Split} method using an async call. - * - * @param client the StringService {@link GrpcServiceClient} - * @throws java.lang.Exception if the call fails - */ - public static void serverStreaming(GrpcServiceClient client) throws Exception { - String stringToSplit = "A B C D E"; - FutureStreamingObserver responses = new FutureStreamingObserver(); - StringMessage request = StringMessage.newBuilder().setText(stringToSplit).build(); - - client.serverStreaming("Split", request, responses); - - // wait for the call to complete - List words = responses.get(); - - for (String word : words) { - System.out.println("Response from async Split: '" + word + "'"); - } - } - - /** - * Call the bidirectional streaming {@code Echo} method using an async call. - * - * @param client the StringService {@link GrpcServiceClient} - * @throws java.lang.Exception if the call fails - */ - public static void bidirectional(GrpcServiceClient client) throws Exception { - List valuesToStream = List.of("A", "B", "C", "D"); - FutureStreamingObserver responses = new FutureStreamingObserver(); - - StreamObserver requests = client.bidiStreaming("Echo", responses); - - // stream the words to the server - valuesToStream.forEach(word -> requests.onNext(StringMessage.newBuilder().setText(word).build())); - // signal that we have completed - requests.onCompleted(); - - // wait for the echo responses to complete - List echoes = responses.get(); - - for (String word : echoes) { - System.out.println("Response from Echo: '" + word + "'"); - } - } - - - /** - * A combination {@link java.util.concurrent.CompletableFuture} and - * {@link io.grpc.stub.StreamObserver}. - *

- * This future will complete when the {@link #onCompleted()} or the - * {@link #onError(Throwable)} methods are called. - *

- * This implementation expects a single result. - */ - static class FutureObserver - extends CompletableFuture - implements StreamObserver { - - private String value; - - public void onNext(StringMessage value) { - this.value = value.getText(); - } - - public void onError(Throwable t) { - completeExceptionally(t); - } - - public void onCompleted() { - complete(value); - } - } - - /** - * A combination {@link java.util.concurrent.CompletableFuture} and - * {@link io.grpc.stub.StreamObserver}. - *

- * This future will complete when the {@link #onCompleted()} or the - * {@link #onError(Throwable)} methods are called. - *

- * This implementation can handle multiple calls to - * {@link #onNext(StringMessage)}. - */ - static class FutureStreamingObserver - extends CompletableFuture> - implements StreamObserver { - - private List values = new ArrayList<>(); - - public void onNext(StringMessage value) { - values.add(value.getText()); - } - - public void onError(Throwable t) { - completeExceptionally(t); - } - - public void onCompleted() { - complete(values); - } - } -} diff --git a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringService.java b/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringService.java deleted file mode 100644 index 9ea651413d1..00000000000 --- a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/StringService.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.common; - -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import io.helidon.grpc.examples.common.Strings.StringMessage; -import io.helidon.grpc.server.CollectingObserver; -import io.helidon.grpc.server.GrpcService; -import io.helidon.grpc.server.ServiceDescriptor; - -import io.grpc.stub.StreamObserver; - -import static io.helidon.grpc.core.ResponseHelper.complete; -import static io.helidon.grpc.core.ResponseHelper.stream; - -/** - * AN implementation of the StringService. - */ -public class StringService - implements GrpcService { - @Override - public void update(ServiceDescriptor.Rules rules) { - rules.proto(Strings.getDescriptor()) - .unary("Upper", this::upper) - .unary("Lower", this::lower) - .serverStreaming("Split", this::split) - .clientStreaming("Join", this::join) - .bidirectional("Echo", this::echo); - } - - // ---- service methods ------------------------------------------------- - - private void upper(StringMessage request, StreamObserver observer) { - complete(observer, response(request.getText().toUpperCase())); - } - - private void lower(StringMessage request, StreamObserver observer) { - complete(observer, response(request.getText().toLowerCase())); - } - - private void split(StringMessage request, StreamObserver observer) { - String[] parts = request.getText().split(" "); - stream(observer, Stream.of(parts).map(this::response)); - } - - private StreamObserver join(StreamObserver observer) { - return new CollectingObserver<>( - Collectors.joining(" "), - observer, - StringMessage::getText, - this::response); - } - - private StreamObserver echo(StreamObserver observer) { - return new StreamObserver() { - public void onNext(StringMessage value) { - observer.onNext(value); - } - - public void onError(Throwable t) { - t.printStackTrace(); - } - - public void onCompleted() { - observer.onCompleted(); - } - }; - } - - // ---- helper methods -------------------------------------------------- - - private StringMessage response(String text) { - return StringMessage.newBuilder().setText(text).build(); - } - -} diff --git a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/package-info.java b/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/package-info.java deleted file mode 100644 index 248bed5fbf1..00000000000 --- a/examples/grpc/common/src/main/java/io/helidon/grpc/examples/common/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Common classes and ProtoBuf generated gRPC servcies used in the Helidon gROC examples. - */ -package io.helidon.grpc.examples.common; diff --git a/examples/grpc/common/src/main/proto/echo.proto b/examples/grpc/common/src/main/proto/echo.proto deleted file mode 100644 index b43f5521565..00000000000 --- a/examples/grpc/common/src/main/proto/echo.proto +++ /dev/null @@ -1,30 +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. - */ - -syntax = "proto3"; -option java_package = "io.helidon.grpc.examples.common"; - -service EchoService { - rpc Echo (EchoRequest) returns (EchoResponse) {} -} - -message EchoRequest { - string message = 1; -} - -message EchoResponse { - string message = 1; -} diff --git a/examples/grpc/common/src/main/proto/greet.proto b/examples/grpc/common/src/main/proto/greet.proto deleted file mode 100644 index a56226ea2ec..00000000000 --- a/examples/grpc/common/src/main/proto/greet.proto +++ /dev/null @@ -1,40 +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. - */ - - -syntax = "proto3"; -option java_package = "io.helidon.grpc.examples.common"; - -service GreetService { - rpc Greet (GreetRequest) returns (GreetResponse) {} - rpc SetGreeting (SetGreetingRequest) returns (SetGreetingResponse) {} -} - -message GreetRequest { - string name = 1; -} - -message GreetResponse { - string message = 1; -} - -message SetGreetingRequest { - string greeting = 1; -} - -message SetGreetingResponse { - string greeting = 1; -} diff --git a/examples/grpc/common/src/main/proto/strings.proto b/examples/grpc/common/src/main/proto/strings.proto deleted file mode 100644 index 77f9a2578d3..00000000000 --- a/examples/grpc/common/src/main/proto/strings.proto +++ /dev/null @@ -1,31 +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. - */ - - -syntax = "proto3"; -option java_package = "io.helidon.grpc.examples.common"; - -service StringService { - rpc Upper (StringMessage) returns (StringMessage) {} - rpc Lower (StringMessage) returns (StringMessage) {} - rpc Split (StringMessage) returns (stream StringMessage) {} - rpc Join (stream StringMessage) returns (StringMessage) {} - rpc Echo (stream StringMessage) returns (stream StringMessage) {} -} - -message StringMessage { - string text = 1; -} diff --git a/examples/grpc/metrics/README.md b/examples/grpc/metrics/README.md deleted file mode 100644 index 8a8265b523d..00000000000 --- a/examples/grpc/metrics/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# Helidon gRPC Metrics Example - -A basic example using metrics with gRPC server. - -## Build and run - -```bash -mvn -f ../pom.xml -pl common,metrics package -java -jar target/helidon-examples-grpc-metrics.jar -``` - -Run the GreetService client: -```bash -java -cp target/helidon-examples-grpc-metrics.jar io.helidon.grpc.examples.common.GreetClient -``` - -Run the StringService client: -```bash -java -cp target/helidon-examples-grpc-metrics.jar io.helidon.grpc.examples.common.StringClient -``` - -Retrieve the metrics: -```bash -curl http://localhost:8080/metrics -``` - -Notice that you will get application metrics from the Helidon server metric response similar to this: -```bash -... -# TYPE application_GreetService_Greet_total counter -# HELP application_GreetService_Greet_total -application_GreetService_Greet_total 2 -# TYPE application_GreetService_SetGreeting_total counter -# HELP application_GreetService_SetGreeting_total -application_GreetService_SetGreeting_total 1 -# TYPE application_StringService_Echo_rate_per_second gauge -application_StringService_Echo_rate_per_second 0.12718615252125942 -# TYPE application_StringService_Echo_one_min_rate_per_second gauge -application_StringService_Echo_one_min_rate_per_second 0.2 -# TYPE application_StringService_Echo_five_min_rate_per_second gauge -application_StringService_Echo_five_min_rate_per_second 0.2 -# TYPE application_StringService_Echo_fifteen_min_rate_per_second gauge -application_StringService_Echo_fifteen_min_rate_per_second 0.2 -# TYPE application_StringService_Echo_mean_seconds gauge -application_StringService_Echo_mean_seconds 0.001451683 -# TYPE application_StringService_Echo_max_seconds gauge -application_StringService_Echo_max_seconds 0.001451683 -# TYPE application_StringService_Echo_min_seconds gauge -application_StringService_Echo_min_seconds 0.001451683 -# TYPE application_StringService_Echo_stddev_seconds gauge -application_StringService_Echo_stddev_seconds 0.0 -# TYPE application_StringService_Echo_seconds summary -# HELP application_StringService_Echo_seconds -application_StringService_Echo_seconds_count 1 -application_StringService_Echo_seconds_sum 0 -application_StringService_Echo_seconds{quantile="0.5"} 0.001451683 -application_StringService_Echo_seconds{quantile="0.75"} 0.001451683 -application_StringService_Echo_seconds{quantile="0.95"} 0.001451683 -application_StringService_Echo_seconds{quantile="0.98"} 0.001451683 -application_StringService_Echo_seconds{quantile="0.99"} 0.001451683 -application_StringService_Echo_seconds{quantile="0.999"} 0.001451683 -# TYPE application_StringService_Join_rate_per_second gauge -application_StringService_Join_rate_per_second 0.25353058349417795 -# TYPE application_StringService_Join_one_min_rate_per_second gauge -application_StringService_Join_one_min_rate_per_second 0.4 -# TYPE application_StringService_Join_five_min_rate_per_second gauge -application_StringService_Join_five_min_rate_per_second 0.4 -# TYPE application_StringService_Join_fifteen_min_rate_per_second gauge -application_StringService_Join_fifteen_min_rate_per_second 0.4 -# TYPE application_StringService_Join_mean_seconds gauge -application_StringService_Join_mean_seconds 0.002281452 -# TYPE application_StringService_Join_max_seconds gauge -application_StringService_Join_max_seconds 0.003709154 -# TYPE application_StringService_Join_min_seconds gauge -application_StringService_Join_min_seconds 8.5375E-4 -# TYPE application_StringService_Join_stddev_seconds gauge -application_StringService_Join_stddev_seconds 0.001427702 -# TYPE application_StringService_Join_seconds summary -# HELP application_StringService_Join_seconds -application_StringService_Join_seconds_count 2 -application_StringService_Join_seconds_sum 0 -application_StringService_Join_seconds{quantile="0.5"} 0.003709154 -application_StringService_Join_seconds{quantile="0.75"} 0.003709154 -application_StringService_Join_seconds{quantile="0.95"} 0.003709154 -application_StringService_Join_seconds{quantile="0.98"} 0.003709154 -application_StringService_Join_seconds{quantile="0.99"} 0.003709154 -application_StringService_Join_seconds{quantile="0.999"} 0.003709154 -# TYPE application_StringService_Lower_rate_per_second gauge -application_StringService_Lower_rate_per_second 0.25274282459020236 -# TYPE application_StringService_Lower_one_min_rate_per_second gauge -application_StringService_Lower_one_min_rate_per_second 0.4 -# TYPE application_StringService_Lower_five_min_rate_per_second gauge -application_StringService_Lower_five_min_rate_per_second 0.4 -# TYPE application_StringService_Lower_fifteen_min_rate_per_second gauge -application_StringService_Lower_fifteen_min_rate_per_second 0.4 -# TYPE application_StringService_Lower_mean_seconds gauge -application_StringService_Lower_mean_seconds 5.606925E-4 -# TYPE application_StringService_Lower_max_seconds gauge -application_StringService_Lower_max_seconds 7.27866E-4 -# TYPE application_StringService_Lower_min_seconds gauge -application_StringService_Lower_min_seconds 3.93519E-4 -# TYPE application_StringService_Lower_stddev_seconds gauge -application_StringService_Lower_stddev_seconds 1.671735E-4 -# TYPE application_StringService_Lower_seconds summary -# HELP application_StringService_Lower_seconds -application_StringService_Lower_seconds_count 2 -application_StringService_Lower_seconds_sum 0 -application_StringService_Lower_seconds{quantile="0.5"} 7.27866E-4 -application_StringService_Lower_seconds{quantile="0.75"} 7.27866E-4 -application_StringService_Lower_seconds{quantile="0.95"} 7.27866E-4 -application_StringService_Lower_seconds{quantile="0.98"} 7.27866E-4 -application_StringService_Lower_seconds{quantile="0.99"} 7.27866E-4 -application_StringService_Lower_seconds{quantile="0.999"} 7.27866E-4 -# TYPE application_StringService_Split_rate_per_second gauge -application_StringService_Split_rate_per_second 0.25378693218040604 -# TYPE application_StringService_Split_one_min_rate_per_second gauge -application_StringService_Split_one_min_rate_per_second 0.4 -# TYPE application_StringService_Split_five_min_rate_per_second gauge -application_StringService_Split_five_min_rate_per_second 0.4 -# TYPE application_StringService_Split_fifteen_min_rate_per_second gauge -application_StringService_Split_fifteen_min_rate_per_second 0.4 -# TYPE application_StringService_Split_mean_seconds gauge -application_StringService_Split_mean_seconds 9.63112E-4 -# TYPE application_StringService_Split_max_seconds gauge -application_StringService_Split_max_seconds 0.001190785 -# TYPE application_StringService_Split_min_seconds gauge -application_StringService_Split_min_seconds 7.35439E-4 -# TYPE application_StringService_Split_stddev_seconds gauge -application_StringService_Split_stddev_seconds 2.27673E-4 -# TYPE application_StringService_Split_seconds summary -# HELP application_StringService_Split_seconds -application_StringService_Split_seconds_count 2 -application_StringService_Split_seconds_sum 0 -application_StringService_Split_seconds{quantile="0.5"} 0.001190785 -application_StringService_Split_seconds{quantile="0.75"} 0.001190785 -application_StringService_Split_seconds{quantile="0.95"} 0.001190785 -application_StringService_Split_seconds{quantile="0.98"} 0.001190785 -application_StringService_Split_seconds{quantile="0.99"} 0.001190785 -application_StringService_Split_seconds{quantile="0.999"} 0.001190785 -# TYPE application_StringService_Upper_mean gauge -application_StringService_Upper_mean 1 -# TYPE application_StringService_Upper_max gauge -application_StringService_Upper_max 1 -# TYPE application_StringService_Upper_min gauge -application_StringService_Upper_min 1 -# TYPE application_StringService_Upper_stddev gauge -application_StringService_Upper_stddev 0 -# TYPE application_StringService_Upper summary -# HELP application_StringService_Upper -application_StringService_Upper_count 1 -application_StringService_Upper_sum 1 -application_StringService_Upper{quantile="0.5"} 1 -application_StringService_Upper{quantile="0.75"} 1 -application_StringService_Upper{quantile="0.95"} 1 -application_StringService_Upper{quantile="0.98"} 1 -application_StringService_Upper{quantile="0.99"} 1 -application_StringService_Upper{quantile="0.999"} 1 -... -``` diff --git a/examples/grpc/metrics/pom.xml b/examples/grpc/metrics/pom.xml deleted file mode 100644 index af2eb0d46e2..00000000000 --- a/examples/grpc/metrics/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-metrics - Helidon gRPC Server Examples Metrics - - - Examples of elementary use of the gRPC Server metrics - - - - io.helidon.grpc.examples.metrics.Server - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.grpc - helidon-grpc-server - - - io.helidon.grpc - helidon-grpc-metrics - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - io.helidon.grpc - helidon-grpc-client - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/Server.java b/examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/Server.java deleted file mode 100644 index 770b37d5573..00000000000 --- a/examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/Server.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.metrics; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.GreetService; -import io.helidon.grpc.examples.common.StringService; -import io.helidon.grpc.metrics.GrpcMetrics; -import io.helidon.grpc.server.GrpcRouting; -import io.helidon.grpc.server.GrpcServer; -import io.helidon.grpc.server.GrpcServerConfiguration; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * A basic example of a Helidon gRPC server. - */ -public class Server { - - private Server() { - } - - /** - * The main program entry point. - * - * @param args the program arguments - * - * @throws Exception if an error occurs - */ - public static void main(String[] args) throws Exception { - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // load logging configuration - LogConfig.configureRuntime(); - - // Get gRPC server config from the "grpc" section of application.yaml - GrpcServerConfiguration serverConfig = - GrpcServerConfiguration.builder(config.get("grpc")).build(); - - GrpcRouting grpcRouting = GrpcRouting.builder() - .intercept(GrpcMetrics.counted()) // global metrics - all service methods counted - .register(new GreetService(config)) // GreetService uses global metrics so all methods are counted - .register(new StringService(), rules -> { - // service level metrics - StringService overrides global so that its methods are timed - rules.intercept(GrpcMetrics.timed()) - // method level metrics - overrides service and global - .intercept("Upper", GrpcMetrics.histogram()); - }) - .build(); - - GrpcServer grpcServer = GrpcServer.create(serverConfig, grpcRouting); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - grpcServer.start() - .thenAccept(s -> { - System.out.println("gRPC server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - // start web server with the metrics endpoints - Routing routing = Routing.builder() - .register(MetricsSupport.create()) - .build(); - - WebServer.create(routing, config.get("webserver")) - .start() - .thenAccept(s -> { - System.out.println("HTTP server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("HTTP server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - } -} diff --git a/examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/package-info.java b/examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/package-info.java deleted file mode 100644 index 8febbc4fb20..00000000000 --- a/examples/grpc/metrics/src/main/java/io/helidon/grpc/examples/metrics/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * An example of gRPC metrics. - *

- * Start with {@link io.helidon.grpc.examples.metrics.Server Main} class. - */ -package io.helidon.grpc.examples.metrics; diff --git a/examples/grpc/metrics/src/main/resources/application.yaml b/examples/grpc/metrics/src/main/resources/application.yaml deleted file mode 100644 index 5a1485a38f4..00000000000 --- a/examples/grpc/metrics/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# 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. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -grpc: - name: "test.server" - port: 1408 - -webserver: - port: 8080 - bind-address: "0.0.0.0" diff --git a/examples/grpc/metrics/src/main/resources/logging.properties b/examples/grpc/metrics/src/main/resources/logging.properties deleted file mode 100644 index f9dfd25b9da..00000000000 --- a/examples/grpc/metrics/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/grpc/microprofile/basic-client/README.md b/examples/grpc/microprofile/basic-client/README.md deleted file mode 100644 index c129bea1380..00000000000 --- a/examples/grpc/microprofile/basic-client/README.md +++ /dev/null @@ -1,40 +0,0 @@ - -# Helidon MP gRPC Client Example - -This examples shows a simple gRPC client application written using Helidon MP. - -This example should be run together with the [Basic Implicit gRPC Server example](../basic-server-implicit/README.md) -which provides the server side implementation of the `StringService` used by this client. The server should be started -before running the client. - -This example shows how a client can be written without needing to write any client side gRPC code. The gRPC service that -the client will use is represented by an annotated interface `io.helidon.microprofile.grpc.example.client.StringService` -which defines all of the methods available on the service deployed on the server. - -## Build -```bash -mvn -f ../../pom.xml -pl common,microprofile/basic-client package -``` - -## Run -Ensure that the server in [Basic Implicit gRPC Server example](../basic-server-implicit/README.md) is started. -Then in this module run: -```bash -java -jar target/helidon-examples-grpc-microprofile-client.jar -``` -Sample output from the client: -```bash -... -Unary Lower response: 'abcd' -Response from blocking Split: 'A' -Response from blocking Split: 'B' -Response from blocking Split: 'C' -Response from blocking Split: 'D' -Response from blocking Split: 'E' -Join response: 'A B C D' -Response from Echo: 'A' -Response from Echo: 'B' -Response from Echo: 'C' -Response from Echo: 'D' -... -``` diff --git a/examples/grpc/microprofile/basic-client/pom.xml b/examples/grpc/microprofile/basic-client/pom.xml deleted file mode 100644 index a109cf82ad0..00000000000 --- a/examples/grpc/microprofile/basic-client/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - helidon-examples-grpc-microprofile-client - Helidon Microprofile gRPC Client Example - - - Microprofile 2.2 gRPC client example - - - - io.helidon.microprofile.grpc.example.client.Client - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.grpc - helidon-microprofile-grpc-client - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncClient.java b/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncClient.java deleted file mode 100644 index 784573164f2..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncClient.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.grpc.example.client; - -import java.util.concurrent.CompletionStage; - -import io.helidon.microprofile.grpc.client.GrpcChannel; -import io.helidon.microprofile.grpc.client.GrpcProxy; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.se.SeContainerInitializer; -import jakarta.inject.Inject; - -/** - * A client to the {@link io.helidon.microprofile.grpc.example.client.AsyncStringService}. - *

- * This client is a CDI bean which will be initialised when the CDI container - * is initialised in the {@link #main(String[])} method. - */ -@ApplicationScoped -public class AsyncClient { - - /** - * The {@link io.helidon.microprofile.grpc.example.client.StringService} client to use to call methods on the server. - *

- * A dynamic proxy of the {@link io.helidon.microprofile.grpc.example.client.StringService} interface will be injected by CDI. - * This proxy will connect to the service using the default {@link io.grpc.Channel}. - */ - @Inject - @GrpcProxy - @GrpcChannel(name = "test-server") - private AsyncStringService stringService; - - - /** - * Program entry point. - * - * @param args the program arguments - * - * @throws Exception if an error occurs - */ - public static void main(String[] args) throws Exception { - SeContainerInitializer initializer = SeContainerInitializer.newInstance(); - SeContainer container = initializer.initialize(); - - AsyncClient client = container.select(AsyncClient.class).get(); - - client.asyncUnary(); - } - - /** - * Call the unary {@code Lower} method. - * @throws java.lang.Exception if the async call fails - */ - void asyncUnary() throws Exception { - CompletionStage response = stringService.lower("ABCD"); - String value = response.toCompletableFuture().get(); - System.out.println("Async Unary Lower response: '" + value + "'"); - } -} diff --git a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncStringService.java b/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncStringService.java deleted file mode 100644 index ec273358bff..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/AsyncStringService.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.grpc.example.client; - -import java.util.concurrent.CompletionStage; -import java.util.stream.Stream; - -import io.helidon.microprofile.grpc.core.Bidirectional; -import io.helidon.microprofile.grpc.core.ClientStreaming; -import io.helidon.microprofile.grpc.core.Grpc; -import io.helidon.microprofile.grpc.core.GrpcMarshaller; -import io.helidon.microprofile.grpc.core.ServerStreaming; -import io.helidon.microprofile.grpc.core.Unary; - -import io.grpc.stub.StreamObserver; - -/** - * The gRPC StringService. - *

- * This class has the {@link io.helidon.microprofile.grpc.core.Grpc} annotation - * so that it will be discovered and loaded using CDI when the MP gRPC server starts. - */ -@Grpc -@GrpcMarshaller("jsonb") -@SuppressWarnings("CdiManagedBeanInconsistencyInspection") -public interface AsyncStringService { - - /** - * Convert a string value to upper case. - * - * @param request the request containing the string to convert - * @return the request value converted to upper case - */ - @Unary - CompletionStage upper(String request); - - /** - * Convert a string value to lower case. - * - * @param request the request containing the string to convert - * @return the request converted to lower case - */ - @Unary - CompletionStage lower(String request); - - /** - * Split a space delimited string value and stream back the split parts. - * @param request the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ServerStreaming - Stream split(String request); - - /** - * Join a stream of string values and return the result. - * @param observer the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ClientStreaming - StreamObserver join(StreamObserver observer); - - /** - * Echo each value streamed from the client back to the client. - * @param observer the {@link io.grpc.stub.StreamObserver} to send responses to - * @return the {@link io.grpc.stub.StreamObserver} to receive requests from - */ - @Bidirectional - StreamObserver echo(StreamObserver observer); -} diff --git a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/Client.java b/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/Client.java deleted file mode 100644 index 28ee2b4369b..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/Client.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.grpc.example.client; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import io.helidon.microprofile.grpc.client.GrpcChannel; -import io.helidon.microprofile.grpc.client.GrpcProxy; - -import io.grpc.stub.StreamObserver; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.se.SeContainerInitializer; -import jakarta.inject.Inject; - -/** - * A client to the {@link StringService}. - *

- * This client is a CDI bean which will be initialised when the CDI container - * is initialised in the {@link #main(String[])} method. - */ -@ApplicationScoped -public class Client { - - /** - * The {@link StringService} client to use to call methods on the server. - *

- * A dynamic proxy of the {@link StringService} interface will be injected by CDI. - * This proxy will connect to the service using the default {@link io.grpc.Channel}. - */ - @Inject - @GrpcProxy - @GrpcChannel(name = "test-server") - private StringService stringService; - - - /** - * Program entry point. - * - * @param args the program arguments - * - * @throws Exception if an error occurs - */ - public static void main(String[] args) throws Exception { - SeContainerInitializer initializer = SeContainerInitializer.newInstance(); - SeContainer container = initializer.initialize(); - - Client client = container.select(Client.class).get(); - - client.unary(); - client.serverStreaming(); - client.clientStreaming(); - client.bidirectional(); - System.exit(0); - } - - /** - * Call the unary {@code Lower} method. - */ - public void unary() { - String response = stringService.lower("ABCD"); - System.out.println("Unary Lower response: '" + response + "'"); - } - - /** - * Call the server streaming {@code Split} method. - */ - public void serverStreaming() { - String stringToSplit = "A B C D E"; - - stringService.split(stringToSplit) - .forEach(response -> System.out.println("Response from blocking Split: '" + response + "'")); - } - - /** - * Call the client streaming {@code Join} method. - * - * @throws Exception if the call fails - */ - public void clientStreaming() throws Exception { - FutureObserver responses = new FutureObserver(); - StreamObserver requests = stringService.join(responses); - - List joinValues = List.of("A", "B", "C", "D"); - - // stream the values to the server - joinValues.forEach(requests::onNext); - requests.onCompleted(); - - // wait for the response observer to complete - String joined = responses.get(); - - System.out.println("Join response: '" + joined + "'"); - } - - /** - * Call the bidirectional streaming {@code Echo} method. - * @throws Exception if the call fails - */ - public void bidirectional() throws Exception { - List valuesToStream = List.of("A", "B", "C", "D"); - FutureStreamingObserver responses = new FutureStreamingObserver(); - - StreamObserver requests = stringService.echo(responses); - - // stream the words to the server - valuesToStream.forEach(requests::onNext); - // signal that we have completed - requests.onCompleted(); - - // wait for the echo responses to complete - List echoes = responses.get(); - - for (String word : echoes) { - System.out.println("Response from Echo: '" + word + "'"); - } - } - - - /** - * A combination {@link java.util.concurrent.CompletableFuture} and - * {@link io.grpc.stub.StreamObserver}. - *

- * This future will complete when the {@link #onCompleted()} or the - * {@link #onError(Throwable)} methods are called. - *

- * This implementation expects a single result. - */ - static class FutureObserver - extends CompletableFuture - implements StreamObserver { - - private String value; - - @Override - public void onNext(String value) { - this.value = value; - } - - @Override - public void onError(Throwable t) { - completeExceptionally(t); - } - - @Override - public void onCompleted() { - complete(value); - } - } - - /** - * A combination {@link java.util.concurrent.CompletableFuture} and - * {@link io.grpc.stub.StreamObserver}. - *

- * This future will complete when the {@link #onCompleted()} or the - * {@link #onError(Throwable)} methods are called. - *

- * This implementation can handle multiple calls to - * {@link #onNext(String)}. - */ - static class FutureStreamingObserver - extends CompletableFuture> - implements StreamObserver { - - private List values = new ArrayList<>(); - - @Override - public void onNext(String value) { - values.add(value); - } - - @Override - public void onError(Throwable t) { - completeExceptionally(t); - } - - @Override - public void onCompleted() { - complete(values); - } - } -} diff --git a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/StringService.java b/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/StringService.java deleted file mode 100644 index c173b236a0f..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/StringService.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.grpc.example.client; - -import java.util.stream.Stream; - -import io.helidon.microprofile.grpc.core.Bidirectional; -import io.helidon.microprofile.grpc.core.ClientStreaming; -import io.helidon.microprofile.grpc.core.Grpc; -import io.helidon.microprofile.grpc.core.GrpcMarshaller; -import io.helidon.microprofile.grpc.core.ServerStreaming; -import io.helidon.microprofile.grpc.core.Unary; - -import io.grpc.stub.StreamObserver; - -/** - * The gRPC StringService. - *

- * This class has the {@link io.helidon.microprofile.grpc.core.Grpc} annotation - * so that it will be discovered and loaded using CDI when the MP gRPC server starts. - */ -@Grpc -@GrpcMarshaller("jsonb") -@SuppressWarnings("CdiManagedBeanInconsistencyInspection") -public interface StringService { - - /** - * Convert a string value to upper case. - * - * @param request the request containing the string to convert - * @return the request value converted to upper case - */ - @Unary - String upper(String request); - - /** - * Convert a string value to lower case. - * - * @param request the request containing the string to convert - * @return the request converted to lower case - */ - @Unary - String lower(String request); - - /** - * Split a space delimited string value and stream back the split parts. - * @param request the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ServerStreaming - Stream split(String request); - - /** - * Join a stream of string values and return the result. - * @param observer the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ClientStreaming - StreamObserver join(StreamObserver observer); - - /** - * Echo each value streamed from the client back to the client. - * @param observer the {@link io.grpc.stub.StreamObserver} to send responses to - * @return the {@link io.grpc.stub.StreamObserver} to receive requests from - */ - @Bidirectional - StreamObserver echo(StreamObserver observer); -} diff --git a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/package-info.java b/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/package-info.java deleted file mode 100644 index 84276232462..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/java/io/helidon/microprofile/grpc/example/client/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Examples of gRPC microprofile clients. - */ -package io.helidon.microprofile.grpc.example.client; diff --git a/examples/grpc/microprofile/basic-client/src/main/resources/META-INF/beans.xml b/examples/grpc/microprofile/basic-client/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 96900241232..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - diff --git a/examples/grpc/microprofile/basic-client/src/main/resources/application.yaml b/examples/grpc/microprofile/basic-client/src/main/resources/application.yaml deleted file mode 100644 index 911ddac31e8..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/resources/application.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -grpc: - channels: - test-server: - host: localhost - port: 1408 - -mp.initializer: - allow: true - no-warn: true diff --git a/examples/grpc/microprofile/basic-client/src/main/resources/logging.properties b/examples/grpc/microprofile/basic-client/src/main/resources/logging.properties deleted file mode 100644 index 785f369b4d6..00000000000 --- a/examples/grpc/microprofile/basic-client/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.config.level=FINEST diff --git a/examples/grpc/microprofile/basic-server-implicit/README.md b/examples/grpc/microprofile/basic-server-implicit/README.md deleted file mode 100644 index 65feee1c30f..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/README.md +++ /dev/null @@ -1,32 +0,0 @@ - -# Helidon MP Implicit gRPC Server Example - -This examples shows a simple gRPC application written using Helidon MP. -It is implicit because in this example you don't write the -`main` class, instead you rely on the Microprofile gRPC Server main class. - -The gRPC services to deploy will be discovered by CDI when the gRPC server starts. -The `StringService` is a POJO service implementation that is annotated with the -CDI qualifier `Grpc` so that it can be discovered. - -Two additional services (`GreetService` and `EchoService`) that are not normally CDI -managed beans are manually added as CDI managed beans in the `AdditionalServices` class -so that they can be discovered. - -This example can be run together with the [Basic gRPC Client example](../basic-client/README.md) -which provides a microprofile gRPC client that uses the services deployed in this server. - -## Build - -```bash -mvn -f ../../pom.xml -pl common,microprofile/basic-server-implicit package -``` - -## Run - -```bash -java -jar target/helidon-examples-grpc-microprofile-basic-implicit.jar -``` - -Then the services can be accessed on the gRPC endpoint `localhost:1408`. As noted above, the client in -[Basic gRPC Client example](../basic-client/README.md) can be used for this purpose. diff --git a/examples/grpc/microprofile/basic-server-implicit/pom.xml b/examples/grpc/microprofile/basic-server-implicit/pom.xml deleted file mode 100644 index ca836285d41..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - helidon-examples-grpc-microprofile-basic-implicit - Helidon Microprofile Examples gRPC Implicit Server - - - Microprofile 2.2 example gRPC server with implicit bootstrapping (server.Main(new String[0]) - - - - io.helidon.microprofile.server.Main - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.grpc - helidon-microprofile-grpc-server - - - io.helidon.microprofile.grpc - helidon-microprofile-grpc-client - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AdditionalServices.java b/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AdditionalServices.java deleted file mode 100644 index 2598dc01f98..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AdditionalServices.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.grpc.example.basic.implicit; - -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.EchoService; -import io.helidon.grpc.examples.common.GreetService; -import io.helidon.microprofile.grpc.server.spi.GrpcMpContext; -import io.helidon.microprofile.grpc.server.spi.GrpcMpExtension; - -/** - * An example of adding additional non-managed bean gRPC services. - *

- * This class is a {@link GrpcMpExtension} that will be called by - * the {@link io.helidon.microprofile.grpc.server.GrpcServerCdiExtension - * gRPC MP Extension} prior to starting the gRPC server. - *

- * As an extension this class also needs to be specified in the - * {@code META-INF/services/io.helidon.microprofile.grpc.server.spi.GrpcMpExtension} - * file (or for Java 9+ modules in the {@code module-info.java} file). - */ -public class AdditionalServices - implements GrpcMpExtension { - /** - * Add additional gRPC services as managed beans. - *

- * These are classes that are on the classpath but for whatever reason are not - * annotated as managed beans (for example we do not own the source) but we want - * them to be located and loaded by the server. - * - * @param context the {@link GrpcMpContext} to use to add the extra services - */ - @Override - public void configure(GrpcMpContext context) { - context.routing() - .register(new GreetService(Config.empty())) - .register(new EchoService()); - } -} diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AsyncStringService.java b/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AsyncStringService.java deleted file mode 100644 index 1be05f6291c..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/AsyncStringService.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.grpc.example.basic.implicit; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import io.helidon.grpc.server.CollectingObserver; -import io.helidon.microprofile.grpc.core.Bidirectional; -import io.helidon.microprofile.grpc.core.ClientStreaming; -import io.helidon.microprofile.grpc.core.Grpc; -import io.helidon.microprofile.grpc.core.GrpcMarshaller; -import io.helidon.microprofile.grpc.core.ServerStreaming; -import io.helidon.microprofile.grpc.core.Unary; - -import io.grpc.stub.StreamObserver; -import jakarta.enterprise.context.ApplicationScoped; - -/** - * The gRPC StringService implementation that uses async unary methods. - *

- * This class is a gRPC service annotated with {@link io.helidon.microprofile.grpc.core.Grpc} and - * {@link jakarta.enterprise.context.ApplicationScoped} so that it will be discovered and deployed using - * CDI when the MP gRPC server starts. - */ -@Grpc -@ApplicationScoped -@GrpcMarshaller("jsonb") -public class AsyncStringService { - - /** - * Convert a string value to upper case asynchronously. - * - * @param request the request containing the string to convert - * @return the request value converted to upper case - */ - @Unary - public CompletionStage upper(String request) { - return CompletableFuture.supplyAsync(request::toUpperCase); - } - - /** - * Convert a string value to lower case. - * - * @param request the request containing the string to convert - * @return the request converted to lower case - */ - @Unary - public CompletionStage lower(String request) { - return CompletableFuture.supplyAsync(request::toLowerCase); - } - - /** - * Split a space delimited string value and stream back the split parts. - * @param request the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ServerStreaming - public Stream split(String request) { - return Stream.of(request.split(" ")); - } - - /** - * Join a stream of string values and return the result. - * @param observer the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ClientStreaming - public StreamObserver join(StreamObserver observer) { - return new CollectingObserver<>(Collectors.joining(" "), observer); - } - - /** - * Echo each value streamed from the client back to the client. - * @param observer the {@link io.grpc.stub.StreamObserver} to send responses to - * @return the {@link io.grpc.stub.StreamObserver} to receive requests from - */ - @Bidirectional - public StreamObserver echo(StreamObserver observer) { - return new EchoObserver(observer); - } - - /** - * Inner StreamObserver used to echo values back to the caller. - */ - private static class EchoObserver - implements StreamObserver { - - private final StreamObserver observer; - - private EchoObserver(StreamObserver observer) { - this.observer = observer; - } - - @Override - public void onNext(String msg) { - observer.onNext(msg); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - } - - @Override - public void onCompleted() { - observer.onCompleted(); - } - } -} diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/StringService.java b/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/StringService.java deleted file mode 100644 index 72986951102..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/StringService.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.grpc.example.basic.implicit; - -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import io.helidon.grpc.server.CollectingObserver; -import io.helidon.microprofile.grpc.core.Bidirectional; -import io.helidon.microprofile.grpc.core.ClientStreaming; -import io.helidon.microprofile.grpc.core.Grpc; -import io.helidon.microprofile.grpc.core.GrpcMarshaller; -import io.helidon.microprofile.grpc.core.ServerStreaming; -import io.helidon.microprofile.grpc.core.Unary; - -import io.grpc.stub.StreamObserver; -import jakarta.enterprise.context.ApplicationScoped; - -/** - * The gRPC StringService implementation. - *

- * This class is a gRPC service annotated with {@link Grpc} and {@link ApplicationScoped} - * so that it will be discovered and deployed using CDI when the MP gRPC server starts. - */ -@Grpc -@ApplicationScoped -@GrpcMarshaller("jsonb") -public class StringService { - - /** - * Convert a string value to upper case. - * - * @param request the request containing the string to convert - * @return the request value converted to upper case - */ - @Unary - public String upper(String request) { - return request.toUpperCase(); - } - - /** - * Convert a string value to lower case. - * - * @param request the request containing the string to convert - * @return the request converted to lower case - */ - @Unary - public String lower(String request) { - return request.toLowerCase(); - } - - /** - * Split a space delimited string value and stream back the split parts. - * @param request the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ServerStreaming - public Stream split(String request) { - return Stream.of(request.split(" ")); - } - - /** - * Join a stream of string values and return the result. - * @param observer the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - */ - @ClientStreaming - public StreamObserver join(StreamObserver observer) { - return new CollectingObserver<>(Collectors.joining(" "), observer); - } - - /** - * Echo each value streamed from the client back to the client. - * @param observer the {@link io.grpc.stub.StreamObserver} to send responses to - * @return the {@link io.grpc.stub.StreamObserver} to receive requests from - */ - @Bidirectional - public StreamObserver echo(StreamObserver observer) { - return new EchoObserver(observer); - } - - /** - * Inner StreamObserver used to echo values back to the caller. - */ - private static class EchoObserver - implements StreamObserver { - - private final StreamObserver observer; - - private EchoObserver(StreamObserver observer) { - this.observer = observer; - } - - @Override - public void onNext(String msg) { - observer.onNext(msg); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - } - - @Override - public void onCompleted() { - observer.onCompleted(); - } - } -} diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/package-info.java b/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/package-info.java deleted file mode 100644 index 4821c2f58b6..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/java/io/helidon/microprofile/grpc/example/basic/implicit/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Examples of implicit gRPC microprofile. - */ -package io.helidon.microprofile.grpc.example.basic.implicit; diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/beans.xml b/examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 8b3c67b427d..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/services/io.helidon.microprofile.grpc.server.spi.GrpcMpExtension b/examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/services/io.helidon.microprofile.grpc.server.spi.GrpcMpExtension deleted file mode 100644 index 951460f787f..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/META-INF/services/io.helidon.microprofile.grpc.server.spi.GrpcMpExtension +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -io.helidon.microprofile.grpc.example.basic.implicit.AdditionalServices diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/application.yaml b/examples/grpc/microprofile/basic-server-implicit/src/main/resources/application.yaml deleted file mode 100644 index 23a6bccfb92..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/application.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -grpc: - name: "test.server" - port: 1408 - -server: - port: 8080 - -tracing: - service: "grpc-server" diff --git a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/logging.properties b/examples/grpc/microprofile/basic-server-implicit/src/main/resources/logging.properties deleted file mode 100644 index 4b50b0d4f83..00000000000 --- a/examples/grpc/microprofile/basic-server-implicit/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.config.level=FINEST diff --git a/examples/grpc/microprofile/metrics/README.md b/examples/grpc/microprofile/metrics/README.md deleted file mode 100644 index 1b82b487b40..00000000000 --- a/examples/grpc/microprofile/metrics/README.md +++ /dev/null @@ -1,101 +0,0 @@ - -# Helidon MP gRPC Server with Metrics and Tracing Example - -This examples shows a simple gRPC application written using Helidon MP that enables -metrics and tracing. - -This example can be run together with the [Basic gRPC Client example](../basic-client/README.md) -which provides a microprofile gRPC client that uses the services deployed in this server. - -## Build and run - -```bash -mvn -f ../../pom.xml -pl common,microprofile/metrics package -java -jar target/helidon-examples-grpc-microprofile-metrics.jar -``` - -Run the basic-client from [Basic gRPC Client example](../basic-client/README.md) to invoke -activity on the gRPC endpoint `localhost:1408`. -```bash -java -jar target/helidon-examples-grpc-microprofile-client.jar -``` - -Retrieve the metrics: -```bash -curl http://localhost:8080/metrics -``` - -Notice that you will get application metrics from the Helidon server metric response similar to this: -```bash -... -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_echo_total counter -# HELP application_io_helidon_microprofile_grpc_example_metrics_StringService_echo_total -application_io_helidon_microprofile_grpc_example_metrics_StringService_echo_total 1 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_join_total counter -# HELP application_io_helidon_microprofile_grpc_example_metrics_StringService_join_total -application_io_helidon_microprofile_grpc_example_metrics_StringService_join_total 1 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_rate_per_second 0.0025970177279218687 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_one_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_one_min_rate_per_second 0.014712537947741825 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_five_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_five_min_rate_per_second 0.0032510706679223173 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_fifteen_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_fifteen_min_rate_per_second 0.0011018917421948848 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_mean_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_mean_seconds 0.023214181 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_max_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_max_seconds 0.023214181 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_min_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_min_seconds 0.023214181 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_stddev_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_stddev_seconds 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds summary -# HELP application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds_count 1 -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds_sum 0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds{quantile="0.5"} 0.023214181 -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds{quantile="0.75"} 0.023214181 -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds{quantile="0.95"} 0.023214181 -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds{quantile="0.98"} 0.023214181 -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds{quantile="0.99"} 0.023214181 -application_io_helidon_microprofile_grpc_example_metrics_StringService_lower_seconds{quantile="0.999"} 0.023214181 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_split_total counter -# HELP application_io_helidon_microprofile_grpc_example_metrics_StringService_split_total -application_io_helidon_microprofile_grpc_example_metrics_StringService_split_total 1 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_split_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_split_rate_per_second 0.002596994840713117 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_split_one_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_split_one_min_rate_per_second 0.014712537947741825 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_split_five_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_split_five_min_rate_per_second 0.0032510706679223173 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_split_fifteen_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_split_fifteen_min_rate_per_second 0.0011018917421948848 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_rate_per_second 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_one_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_one_min_rate_per_second 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_five_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_five_min_rate_per_second 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_fifteen_min_rate_per_second gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_fifteen_min_rate_per_second 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_mean_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_mean_seconds 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_max_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_max_seconds 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_min_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_min_seconds 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_stddev_seconds gauge -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_stddev_seconds 0.0 -# TYPE application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds summary -# HELP application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds_count 0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds_sum 0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds{quantile="0.5"} 0.0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds{quantile="0.75"} 0.0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds{quantile="0.95"} 0.0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds{quantile="0.98"} 0.0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds{quantile="0.99"} 0.0 -application_io_helidon_microprofile_grpc_example_metrics_StringService_upper_seconds{quantile="0.999"} 0.0 -... -``` diff --git a/examples/grpc/microprofile/metrics/pom.xml b/examples/grpc/microprofile/metrics/pom.xml deleted file mode 100644 index cc7e56f0103..00000000000 --- a/examples/grpc/microprofile/metrics/pom.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - helidon-examples-grpc-microprofile-metrics - Helidon Microprofile Examples gRPC Metrics - - - Microprofile 2.2 example gRPC server with metrics - - - - io.helidon.microprofile.server.Main - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.grpc - helidon-microprofile-grpc-server - - - io.helidon.microprofile.grpc - helidon-microprofile-grpc-metrics - - - io.helidon.microprofile.grpc - helidon-microprofile-grpc-client - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/StringService.java b/examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/StringService.java deleted file mode 100644 index f63149f8cfb..00000000000 --- a/examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/StringService.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.grpc.example.metrics; - -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import io.helidon.grpc.server.CollectingObserver; -import io.helidon.microprofile.grpc.core.Bidirectional; -import io.helidon.microprofile.grpc.core.ClientStreaming; -import io.helidon.microprofile.grpc.core.Grpc; -import io.helidon.microprofile.grpc.core.GrpcMarshaller; -import io.helidon.microprofile.grpc.core.ServerStreaming; -import io.helidon.microprofile.grpc.core.Unary; - -import io.grpc.stub.StreamObserver; -import jakarta.enterprise.context.ApplicationScoped; -import org.eclipse.microprofile.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.Metered; -import org.eclipse.microprofile.metrics.annotation.Timed; - -/** - * The gRPC StringService implementation. - *

- * This class is a gRPC service annotated with {@link io.helidon.microprofile.grpc.core.Grpc} - * and {@link jakarta.enterprise.context.ApplicationScoped} so that it will be discovered and deployed - * using CDI when the MP gRPC server starts. - */ -@Grpc -@GrpcMarshaller("jsonb") -@ApplicationScoped -public class StringService { - - /** - * Convert a string value to upper case. - *

- * This method is annotated with {@literal @}{@link Timed} so a - * gRPC metrics {@link io.grpc.ServerInterceptor} will be added - * by the gRPC metrics CDI extension. - * - * @param request the request containing the string to convert - * @return the request value converted to upper case - */ - @Unary - @Timed - public String upper(String request) { - return request.toUpperCase(); - } - - /** - * Convert a string value to lower case. - *

- * This method is annotated with {@literal @}{@link Timed} so a - * gRPC metrics {@link io.grpc.ServerInterceptor} will be added - * by the gRPC metrics CDI extension. - * - * @param request the request containing the string to convert - * @return the request converted to lower case - */ - @Unary - @Timed - public String lower(String request) { - return request.toLowerCase(); - } - - /** - * Split a space delimited string value and stream back the split parts. - * @param request the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - *

- * This method is annotated with {@literal @}{@link Metered} so a - * gRPC metrics {@link io.grpc.ServerInterceptor} will be added - * by the gRPC metrics CDI extension. - */ - @ServerStreaming - @Metered - public Stream split(String request) { - return Stream.of(request.split(" ")); - } - - /** - * Join a stream of string values and return the result. - * @param observer the request containing the string to split - * @return a {@link java.util.stream.Stream} containing the split parts - *

- * This method is annotated with {@literal @}{@link Counted} so a - * gRPC metrics {@link io.grpc.ServerInterceptor} will be added - * by the gRPC metrics CDI extension. - */ - @ClientStreaming - @Counted - public StreamObserver join(StreamObserver observer) { - return new CollectingObserver<>(Collectors.joining(" "), observer); - } - - /** - * Echo each value streamed from the client back to the client. - * @param observer the {@link io.grpc.stub.StreamObserver} to send responses to - * @return the {@link io.grpc.stub.StreamObserver} to receive requests from - *

- * This method is annotated with {@literal @}{@link Counted} so a - * gRPC metrics {@link io.grpc.ServerInterceptor} will be added - * by the gRPC metrics CDI extension. - */ - @Bidirectional - @Counted - public StreamObserver echo(StreamObserver observer) { - return new EchoObserver(observer); - } - - /** - * Inner StreamObserver used to echo values back to the caller. - */ - private static class EchoObserver - implements StreamObserver { - - private final StreamObserver observer; - - private EchoObserver(StreamObserver observer) { - this.observer = observer; - } - - @Override - public void onNext(String msg) { - observer.onNext(msg); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - } - - @Override - public void onCompleted() { - observer.onCompleted(); - } - } -} diff --git a/examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/package-info.java b/examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/package-info.java deleted file mode 100644 index 4958c4b0219..00000000000 --- a/examples/grpc/microprofile/metrics/src/main/java/io/helidon/microprofile/grpc/example/metrics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Examples of gRPC microprofile metrics. - */ -package io.helidon.microprofile.grpc.example.metrics; diff --git a/examples/grpc/microprofile/metrics/src/main/resources/META-INF/beans.xml b/examples/grpc/microprofile/metrics/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 8b3c67b427d..00000000000 --- a/examples/grpc/microprofile/metrics/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - diff --git a/examples/grpc/microprofile/metrics/src/main/resources/application.yaml b/examples/grpc/microprofile/metrics/src/main/resources/application.yaml deleted file mode 100644 index 23a6bccfb92..00000000000 --- a/examples/grpc/microprofile/metrics/src/main/resources/application.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -grpc: - name: "test.server" - port: 1408 - -server: - port: 8080 - -tracing: - service: "grpc-server" diff --git a/examples/grpc/microprofile/metrics/src/main/resources/logging.properties b/examples/grpc/microprofile/metrics/src/main/resources/logging.properties deleted file mode 100644 index c7df340437a..00000000000 --- a/examples/grpc/microprofile/metrics/src/main/resources/logging.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.config.level=FINEST -io.helidon.microprofile.metrics.level=FINEST -io.helidon.microprofile.grpc.metrics.level=FINEST diff --git a/examples/grpc/microprofile/pom.xml b/examples/grpc/microprofile/pom.xml deleted file mode 100644 index 9de0df09e06..00000000000 --- a/examples/grpc/microprofile/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.grpc - helidon-examples-grpc-project - 3.2.7-SNAPSHOT - - pom - io.helidon.examples.grpc.microprofile - helidon-examples-grpc-microprofile-project - Helidon gRPC Microprofile Examples - - - basic-client - basic-server-implicit - metrics - - diff --git a/examples/grpc/opentracing/README.md b/examples/grpc/opentracing/README.md deleted file mode 100644 index 94fb16ff690..00000000000 --- a/examples/grpc/opentracing/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Opentracing gRPC Server Example Application - -## Start Zipkin - -With Docker: -```bash -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -``` - -```bash -curl -sSL https://zipkin.io/quickstart.sh | bash -s -java -jar zipkin.jar -``` - -## Build and run -```bash -mvn -f ../pom.xml -pl common,opentracing package -java -jar target/helidon-examples-grpc-opentracing.jar -``` - -Exercise the gRPC endpoint with GreeClient and StringClient: -```bash -java -cp target/helidon-examples-grpc-opentracing.jar io.helidon.grpc.examples.common.GreetClient -java -cp target/helidon-examples-grpc-opentracing.jar io.helidon.grpc.examples.common.StringClient -``` - -Then check out the traces at http://localhost:9411 from a browser. - -Stop zipkin if run with the docker container: -```bash -docker stop zipkin && docker rm zipkin -``` diff --git a/examples/grpc/opentracing/pom.xml b/examples/grpc/opentracing/pom.xml deleted file mode 100644 index ac8ff37b4d5..00000000000 --- a/examples/grpc/opentracing/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-opentracing - Helidon gRPC Server Examples OpenTracing - - - Examples gRPC application using Open Tracing - - - - io.helidon.grpc.examples.opentracing.ZipkinExampleMain - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.grpc - helidon-grpc-server - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.grpc - helidon-grpc-client - - - io.helidon.tracing - helidon-tracing-zipkin - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/ZipkinExampleMain.java b/examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/ZipkinExampleMain.java deleted file mode 100644 index 7b211b3175e..00000000000 --- a/examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/ZipkinExampleMain.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.opentracing; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.GreetService; -import io.helidon.grpc.examples.common.StringService; -import io.helidon.grpc.server.GrpcRouting; -import io.helidon.grpc.server.GrpcServer; -import io.helidon.grpc.server.GrpcServerConfiguration; -import io.helidon.grpc.server.GrpcTracingConfig; -import io.helidon.grpc.server.ServerRequestAttribute; -import io.helidon.tracing.Tracer; -import io.helidon.tracing.TracerBuilder; - -/** - * An example gRPC server with Zipkin tracing enabled. - */ -public class ZipkinExampleMain { - - private ZipkinExampleMain() { - } - - /** - * Program entry point. - * - * @param args the program command line arguments - * @throws Exception if there is a program error - */ - public static void main(String[] args) throws Exception { - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // load logging configuration - LogConfig.configureRuntime(); - - Tracer tracer = TracerBuilder.create(config.get("tracing")).build(); - - GrpcTracingConfig tracingConfig = GrpcTracingConfig.builder() - .withStreaming() - .withVerbosity() - .withTracedAttributes(ServerRequestAttribute.CALL_ATTRIBUTES, - ServerRequestAttribute.HEADERS, - ServerRequestAttribute.METHOD_NAME) - .build(); - - // Get gRPC server config from the "grpc" section of application.yaml - GrpcServerConfiguration serverConfig = - GrpcServerConfiguration.builder(config.get("grpc")).tracer(tracer).tracingConfig(tracingConfig).build(); - - GrpcServer grpcServer = GrpcServer.create(serverConfig, createRouting(config)); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - grpcServer.start() - .thenAccept(s -> { - System.out.println("gRPC server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - } - - private static GrpcRouting createRouting(Config config) { - return GrpcRouting.builder() - .register(new GreetService(config)) - .register(new StringService()) - .build(); - } -} diff --git a/examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/package-info.java b/examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/package-info.java deleted file mode 100644 index 880286f3075..00000000000 --- a/examples/grpc/opentracing/src/main/java/io/helidon/grpc/examples/opentracing/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A set of small usage examples of running the Helidon gRPC server with Zipkin tracing enabled. - */ -package io.helidon.grpc.examples.opentracing; diff --git a/examples/grpc/opentracing/src/main/resources/application.yaml b/examples/grpc/opentracing/src/main/resources/application.yaml deleted file mode 100644 index fcba9d211c0..00000000000 --- a/examples/grpc/opentracing/src/main/resources/application.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -grpc: - name: "test.server" - port: 1408 - -webserver: - port: 8080 - bind-address: "0.0.0.0" - -tracing: - host: "localhost" - service: "grpc-server" diff --git a/examples/grpc/opentracing/src/main/resources/logging.properties b/examples/grpc/opentracing/src/main/resources/logging.properties deleted file mode 100644 index f9dfd25b9da..00000000000 --- a/examples/grpc/opentracing/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/grpc/pom.xml b/examples/grpc/pom.xml deleted file mode 100644 index 0116dcda2e0..00000000000 --- a/examples/grpc/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.grpc - helidon-examples-grpc-project - pom - Helidon gRPC Examples - - - common - basics - metrics - opentracing - security - security-abac - security-outbound - microprofile - client-standalone - - diff --git a/examples/grpc/security-abac/README.md b/examples/grpc/security-abac/README.md deleted file mode 100644 index 7767713b838..00000000000 --- a/examples/grpc/security-abac/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Helidon gRPC Security ABAC Example - -An example gRPC server for attribute based access control. - -## Build and run -Build: -```bash -mvn -f ../pom.xml -pl common,security-abac package -``` - -Run using programmatic ABAC setup(see [AbacServer.java](src/main/java/io/helidon/grpc/examples/security/abac/AbacServer.java)): -```bash -java -jar target/helidon-examples-grpc-security-abac.jar -``` - -Run using ABAC config setup (see [application.yaml](src/main/resources/application.yaml)): -```bash -java -cp target/helidon-examples-grpc-security-abac.jar \ - io.helidon.grpc.examples.security.abac.AbacServerFromConfig -``` - -Exercise the example using SecureStringClient: -```bash -java -cp target/helidon-examples-grpc-security-abac.jar \ - io.helidon.grpc.examples.security.abac.SecureStringClient -``` - -The client will only fail if parameters are not within the ABAC attributes setup. For example, below failed -because the request was made outside the `time-of-day` attribute range: -```bash -Jul 20, 2022 12:27:39 PM io.helidon.security.DefaultAuditProvider lambda$logEvent$1 -FINEST: FAILURE authz.authorize 71e94b20-961c-4123-8f8b-ad8c365b8f80:1 io.helidon.common.context.Contexts runInContext Contexts.java 117 :: "Path Optional[StringService/Upper]. Provider io.helidon.security.providers.abac.AbacProvider, Description io.helidon.security.AuthorizationClientImpl@186478ad, Request Optional[Subject: Principal: Principal{properties=BasicAttributes{registry={name=user, id=user}}, name='user', id='user'} Principal: role:user_role Principal: scope:calendar_read Principal: scope:calendar_edit ]. Subject FATAL: 12:27:38 is in neither of allowed times: [08:15 - 12:00, 12:30 - 17:30] at io.helidon.security.abac.time.TimeValidator@72486851" -Jul 20, 2022 12:27:39 PM io.helidon.security.DefaultAuditProvider lambda$logEvent$1 -FINEST: FAILURE grpcRequest 71e94b20-961c-4123-8f8b-ad8c365b8f80:1 io.helidon.security.integration.grpc.GrpcSecurityHandler processAudit GrpcSecurityHandler.java 442 :: "PERMISSION_DENIED StringService/Upper grpc grpc requested by Subject: Principal: Principal{properties=BasicAttributes{registry={name=user, id=user}}, name='user', id='user'} Principal: role:user_role Principal: scope:calendar_read Principal: scope:calendar_edit " -``` diff --git a/examples/grpc/security-abac/pom.xml b/examples/grpc/security-abac/pom.xml deleted file mode 100644 index 120312b35fa..00000000000 --- a/examples/grpc/security-abac/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-security-abac - Helidon gRPC Server Examples ABAC Security - - - Examples of securing gRPC services using ABAC - - - - io.helidon.grpc.examples.security.abac.AbacServer - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.grpc - helidon-grpc-core - - - io.helidon.grpc - helidon-grpc-server - - - io.helidon.security.integration - helidon-security-integration-grpc - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.bundles - helidon-bundles-security - - - io.helidon.security.abac - helidon-security-abac-policy-el - - - org.glassfish - jakarta.el - - - io.helidon.grpc - helidon-grpc-client - - - io.grpc - grpc-netty - - - io.grpc - grpc-services - - - io.grpc - grpc-protobuf - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServer.java b/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServer.java deleted file mode 100644 index a5d3374cba1..00000000000 --- a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServer.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security.abac; - -import java.time.DayOfWeek; -import java.time.LocalTime; - -import io.helidon.common.LogConfig; -import io.helidon.grpc.examples.common.StringService; -import io.helidon.grpc.server.GrpcRouting; -import io.helidon.grpc.server.GrpcServer; -import io.helidon.grpc.server.GrpcServerConfiguration; -import io.helidon.grpc.server.ServiceDescriptor; -import io.helidon.security.Security; -import io.helidon.security.SubjectType; -import io.helidon.security.abac.policy.PolicyValidator; -import io.helidon.security.abac.scope.ScopeValidator; -import io.helidon.security.abac.time.TimeValidator; -import io.helidon.security.integration.grpc.GrpcSecurity; -import io.helidon.security.providers.abac.AbacProvider; - -/** - * An example of a secure gRPC server that uses - * ABAC security configured in the code below. - *

- * This server configures in code the same rules that - * the {@link AbacServerFromConfig} class uses from - * its configuration. - */ -public class AbacServer { - - private AbacServer() { - } - - /** - * Main entry point. - * - * @param args the program arguments - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Security security = Security.builder() - .addProvider(AtnProvider.builder().build()) // add out custom provider - .addProvider(AbacProvider.builder().build()) // add the ABAC provider - .build(); - - // Create the time validator that will be used by the ABAC security provider - TimeValidator.TimeConfig validTimes = TimeValidator.TimeConfig.builder() - .addBetween(LocalTime.of(8, 15), LocalTime.of(12, 0)) - .addBetween(LocalTime.of(12, 30), LocalTime.of(17, 30)) - .addDaysOfWeek(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY) - .build(); - - // Create the policy validator that will be used by the ABAC security provider - PolicyValidator.PolicyConfig validPolicy = PolicyValidator.PolicyConfig.builder() - .statement("${env.time.year >= 2017}") - .build(); - - // Create the scope validator that will be used by the ABAC security provider - ScopeValidator.ScopesConfig validScopes = ScopeValidator.ScopesConfig.create("calendar_read", "calendar_edit"); - - // Create the Atn config that will be used by out custom security provider - AtnProvider.AtnConfig atnConfig = AtnProvider.AtnConfig.builder() - .addAuth(AtnProvider.Auth.builder("user") - .type(SubjectType.USER) - .roles("user_role") - .scopes("calendar_read", "calendar_edit") - .build()) - .addAuth(AtnProvider.Auth.builder("service") - .type(SubjectType.SERVICE) - .roles("service_role") - .scopes("calendar_read", "calendar_edit") - .build()) - .build(); - - ServiceDescriptor stringService = ServiceDescriptor.builder(new StringService()) - .intercept("Upper", GrpcSecurity.secure() - .customObject(atnConfig) - .customObject(validScopes) - .customObject(validTimes) - .customObject(validPolicy)) - .build(); - - GrpcRouting grpcRouting = GrpcRouting.builder() - .intercept(GrpcSecurity.create(security).securityDefaults(GrpcSecurity.secure())) - .register(stringService) - .build(); - - GrpcServerConfiguration serverConfig = GrpcServerConfiguration.builder().build(); - GrpcServer grpcServer = GrpcServer.create(serverConfig, grpcRouting); - - grpcServer.start() - .thenAccept(s -> { - System.out.println("gRPC server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - } -} diff --git a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServerFromConfig.java b/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServerFromConfig.java deleted file mode 100644 index 500560da33f..00000000000 --- a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AbacServerFromConfig.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security.abac; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.StringService; -import io.helidon.grpc.server.GrpcRouting; -import io.helidon.grpc.server.GrpcServer; -import io.helidon.grpc.server.GrpcServerConfiguration; -import io.helidon.security.Security; -import io.helidon.security.integration.grpc.GrpcSecurity; - -/** - * An example of a secure gRPC server that uses ABAC - * security configured from configuration the configuration - * file application.conf. - *

- * This server's configuration file configures security with - * same rules that the {@link AbacServer} class builds in - * code. - */ -public class AbacServerFromConfig { - - private AbacServerFromConfig() { - } - - /** - * Main entry point. - * - * @param args the program arguments - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Config config = Config.create(); - - Security security = Security.create(config.get("security")); - - GrpcRouting grpcRouting = GrpcRouting.builder() - .intercept(GrpcSecurity.create(security, config.get("security"))) - .register(new StringService()) - .build(); - - GrpcServerConfiguration serverConfig = GrpcServerConfiguration.create(config.get("grpc")); - GrpcServer grpcServer = GrpcServer.create(serverConfig, grpcRouting); - - grpcServer.start() - .thenAccept(s -> { - System.out.println("gRPC server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - } -} diff --git a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProvider.java b/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProvider.java deleted file mode 100644 index 5c3febccd5e..00000000000 --- a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProvider.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security.abac; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.config.Config; -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Grant; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Role; -import io.helidon.security.Subject; -import io.helidon.security.SubjectType; -import io.helidon.security.spi.AuthenticationProvider; -import io.helidon.security.spi.SynchronousProvider; - -/** - * Example authentication provider that reads annotation to create a subject. - */ -public class AtnProvider extends SynchronousProvider implements AuthenticationProvider { - - /** - * The configuration key for this provider. - */ - public static final String CONFIG_KEY = "atn"; - - private final Config config; - - private AtnProvider(Config config) { - this.config = config; - } - - @Override - protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { - EndpointConfig endpointConfig = providerRequest.endpointConfig(); - Config atnConfig = endpointConfig.config(CONFIG_KEY).orElse(null); - Subject user = null; - Subject service = null; - List list; - - Optional optional = providerRequest.endpointConfig().instance(AtnConfig.class); - - if (optional.isPresent()) { - list = optional.get().auths(); - } else if (atnConfig != null && !atnConfig.isLeaf()) { - list = atnConfig.asNodeList() - .map(this::fromConfig).orElse(Collections.emptyList()); - } else { - list = fromAnnotations(endpointConfig); - } - - for (Auth authentication : list) { - if (authentication.type() == SubjectType.USER) { - user = buildSubject(authentication); - } else { - service = buildSubject(authentication); - } - } - - return AuthenticationResponse.success(user, service); - } - - private List fromConfig(List configList) { - return configList.stream() - .map(Auth::new) - .collect(Collectors.toList()); - } - - private List fromAnnotations(EndpointConfig endpointConfig) { - return endpointConfig.securityLevels() - .stream() - .flatMap(level -> level.combineAnnotations(Authentications.class, EndpointConfig.AnnotationScope.METHOD).stream()) - .map(Authentications::value) - .flatMap(Arrays::stream) - .map(Auth::new) - .collect(Collectors.toList()); - } - - private Subject buildSubject(Auth authentication) { - Subject.Builder subjectBuilder = Subject.builder(); - - subjectBuilder.principal(Principal.create(authentication.principal())); - - Arrays.stream(authentication.roles()) - .map(Role::create) - .forEach(subjectBuilder::addGrant); - - Arrays.stream(authentication.scopes()) - .map(scope -> Grant.builder().name(scope).type("scope").build()) - .forEach(subjectBuilder::addGrant); - - return subjectBuilder.build(); - } - - @Override - public Collection> supportedAnnotations() { - return Set.of(Authentication.class); - } - - /** - * Create a {@link AtnProvider}. - * @return a {@link AtnProvider} - */ - public static AtnProvider create() { - return builder().build(); - } - - /** - * Create a {@link AtnProvider}. - * - * @param config the configuration for the {@link AtnProvider} - * - * @return a {@link AtnProvider} - */ - public static AtnProvider create(Config config) { - return builder(config).build(); - } - - /** - * Create a {@link AtnProvider.Builder}. - * @return a {@link AtnProvider.Builder} - */ - public static Builder builder() { - return builder(null); - } - - /** - * Create a {@link AtnProvider.Builder}. - * - * @param config the configuration for the {@link AtnProvider} - * - * @return a {@link AtnProvider.Builder} - */ - public static Builder builder(Config config) { - return new Builder(config); - } - - /** - * A builder that builds {@link AtnProvider} instances. - */ - public static class Builder - implements io.helidon.common.Builder { - - private Config config; - - private Builder(Config config) { - this.config = config; - } - - /** - * Set the configuration for the {@link AtnProvider}. - * @param config the configuration for the {@link AtnProvider} - * @return this builder - */ - public Builder config(Config config) { - this.config = config; - return this; - } - - @Override - public AtnProvider build() { - return new AtnProvider(config); - } - } - - /** - * Authentication annotation. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @Documented - @Inherited - @Repeatable(Authentications.class) - public @interface Authentication { - /** - * Name of the principal. - * - * @return principal name - */ - String value(); - - /** - * Type of the subject, defaults to user. - * - * @return type - */ - SubjectType type() default SubjectType.USER; - - /** - * Granted roles. - * @return array of roles - */ - String[] roles() default ""; - - /** - * Granted scopes. - * @return array of scopes - */ - String[] scopes() default ""; - } - - /** - * Repeatable annotation for {@link Authentication}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @Documented - @Inherited - public @interface Authentications { - /** - * Repeating annotation. - * @return annotations - */ - Authentication[] value(); - } - - /** - * A holder for authentication settings. - */ - public static class Auth { - private String principal; - private SubjectType type = SubjectType.USER; - private String[] roles; - private String[] scopes; - - private Auth(Authentication authentication) { - principal = authentication.value(); - type = authentication.type(); - roles = authentication.roles(); - scopes = authentication.scopes(); - } - - private Auth(Config config) { - config.get("principal").ifExists(cfg -> principal = cfg.asString().get()); - config.get("type").ifExists(cfg -> type = SubjectType.valueOf(cfg.asString().get())); - config.get("roles").ifExists(cfg -> roles = cfg.asList(String.class).get().toArray(new String[0])); - config.get("scopes").ifExists(cfg -> scopes = cfg.asList(String.class).get().toArray(new String[0])); - } - - private Auth(String principal, SubjectType type, String[] roles, String[] scopes) { - this.principal = principal; - this.type = type; - this.roles = roles; - this.scopes = scopes; - } - - private String principal() { - return principal; - } - - private SubjectType type() { - return type; - } - - private String[] roles() { - return roles; - } - - private String[] scopes() { - return scopes; - } - - /** - * Obtain a builder for building {@link Auth} instances. - * - * @param principal the principal name - * - * @return a builder for building {@link Auth} instances. - */ - public static Builder builder(String principal) { - return new Auth.Builder(principal); - } - - /** - * A builder for building {@link Auth} instances. - */ - public static class Builder - implements io.helidon.common.Builder { - - private final String principal; - private SubjectType type = SubjectType.USER; - private String[] roles; - private String[] scopes; - - private Builder(String principal) { - this.principal = principal; - } - - /** - * Set the {@link SubjectType}. - * @param type the {@link SubjectType} - * @return this builder - */ - public Builder type(SubjectType type) { - this.type = type; - return this; - } - - /** - * Set the roles. - * @param roles the role names - * @return this builder - */ - public Builder roles(String... roles) { - this.roles = roles; - return this; - } - - /** - * Set the scopes. - * @param scopes the scopes names - * @return this builder - */ - public Builder scopes(String... scopes) { - this.scopes = scopes; - return this; - } - - @Override - public Auth build() { - return new Auth(principal, type, roles, scopes); - } - } - } - - /** - * The configuration for a {@link AtnProvider}. - */ - public static class AtnConfig { - private final List authData; - - private AtnConfig(List list) { - this.authData = list; - } - - /** - * Obtain the {@link List} of {@link Auth}s to use. - * - * @return the {@link List} of {@link Auth}s to use - */ - public List auths() { - return Collections.unmodifiableList(authData); - } - - /** - * Obtain a builder for building {@link AtnConfig} instances. - * - * @return a builder for building {@link AtnConfig} instances - */ - public static AtnConfig.Builder builder() { - return new Builder(); - } - - /** - * A builder for building {@link AtnConfig} instances. - */ - public static class Builder - implements io.helidon.common.Builder { - - private final List authData = new ArrayList<>(); - - /** - * Add an {@link Auth} instance. - * - * @param auth the {@link Auth} to add - * - * @return this builder - * - * @throws java.lang.NullPointerException if the {@link Auth} is null - */ - public Builder addAuth(Auth auth) { - authData.add(Objects.requireNonNull(auth)); - return this; - } - - @Override - public AtnConfig build() { - return new AtnConfig(authData); - } - } - } -} diff --git a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProviderService.java b/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProviderService.java deleted file mode 100644 index 85307367e3f..00000000000 --- a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/AtnProviderService.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security.abac; - -import io.helidon.config.Config; -import io.helidon.security.spi.SecurityProvider; -import io.helidon.security.spi.SecurityProviderService; - -/** - * A service provider for the {@link AtnProvider}. - */ -public class AtnProviderService - implements SecurityProviderService { - - @Override - public String providerConfigKey() { - return AtnProvider.CONFIG_KEY; - } - - @Override - public Class providerClass() { - return AtnProvider.class; - } - - @Override - public SecurityProvider providerInstance(Config config) { - return AtnProvider.create(config); - } -} diff --git a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/SecureStringClient.java b/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/SecureStringClient.java deleted file mode 100644 index f156999e09e..00000000000 --- a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/SecureStringClient.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security.abac; - - -import io.helidon.grpc.examples.common.StringServiceGrpc; -import io.helidon.grpc.examples.common.Strings; - -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; - -/** - * A {@link io.helidon.grpc.examples.common.StringService} client that optionally - * provides {@link io.grpc.CallCredentials} using basic auth. - */ -public class SecureStringClient { - - private SecureStringClient() { - } - - /** - * Program entry point. - * - * @param args program arguments - */ - public static void main(String[] args) { - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - StringServiceGrpc.StringServiceBlockingStub stub = StringServiceGrpc.newBlockingStub(channel); - - String text = "abcde"; - Strings.StringMessage request = Strings.StringMessage.newBuilder().setText(text).build(); - Strings.StringMessage response = stub.upper(request); - - System.out.println("Text '" + text + "' to upper is '" + response.getText() + "'"); - } -} diff --git a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/package-info.java b/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/package-info.java deleted file mode 100644 index 06f2d88fe3f..00000000000 --- a/examples/grpc/security-abac/src/main/java/io/helidon/grpc/examples/security/abac/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A set of small usage examples. Start with {@link io.helidon.grpc.examples.security.SecureServer Main} class. - */ -package io.helidon.grpc.examples.security.abac; diff --git a/examples/grpc/security-abac/src/main/resources/META-INF/native-image/helidon-examples/grpc-security-abac/reflect-config.json b/examples/grpc/security-abac/src/main/resources/META-INF/native-image/helidon-examples/grpc-security-abac/reflect-config.json deleted file mode 100644 index 369ae4bec39..00000000000 --- a/examples/grpc/security-abac/src/main/resources/META-INF/native-image/helidon-examples/grpc-security-abac/reflect-config.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - { - "name": "java.time.ZonedDateTime", - "methods": [ - { - "name": "getYear", - "parameterTypes": [] - } - ] - } -] \ No newline at end of file diff --git a/examples/grpc/security-abac/src/main/resources/META-INF/services/io.helidon.security.spi.SecurityProviderService b/examples/grpc/security-abac/src/main/resources/META-INF/services/io.helidon.security.spi.SecurityProviderService deleted file mode 100644 index 7888a0af2d7..00000000000 --- a/examples/grpc/security-abac/src/main/resources/META-INF/services/io.helidon.security.spi.SecurityProviderService +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -io.helidon.grpc.examples.security.abac.AtnProviderService \ No newline at end of file diff --git a/examples/grpc/security-abac/src/main/resources/application.yaml b/examples/grpc/security-abac/src/main/resources/application.yaml deleted file mode 100644 index dbc6e7f277e..00000000000 --- a/examples/grpc/security-abac/src/main/resources/application.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# -# 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. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -grpc: - port: 1408 - -security: - providers: - - abac: - # prepares environment - # executes attribute validations - # validates that attributes were processed - # grants/denies access to resource - # - #### - # Combinations: - # # Will fail if any attribute is not validated and if any has failed validation - # fail-on-unvalidated: true - # fail-if-none-validated: true - # - # # Will fail if there is one or more attributes present and NONE of them is validated or if any has failed validation - # # Will NOT fail if there is at least one validated attribute and any number of not validated attributes (and NONE failed) - # fail-on-unvalidated: false - # fail-if-none-validated: true - # - # # Will fail if there is any attribute that failed validation - # # Will NOT fail if there are no failed validation or if there are NONE validated - # fail-on-unvalidated: false - # fail-if-none-validated: false - #### - # fail if an attribute was not validated (e.g. we do not know, whether it is valid or not) - # defaults to true - fail-on-unvalidated: true - # fail if none of the attributes were validated - # defaults to true - fail-if-none-validated: true - - atn: - class: "io.helidon.grpc.examples.security.abac.AtnProvider" - - grpc-server: - # Configuration of integration with grpc server - # The default configuration to apply to all services not explicitly configured below - defaults: - authenticate: true - authorize: true - services: - - name: "StringService" - methods: - - name: "Upper" - # Define our custom authenticator rules for the Upper method - atn: - - principal: "user" - type: "USER" - roles: ["user_role"] - scopes: ["calendar_read", "calendar_edit"] - - principal: "service" - type: "SERVICE" - roles: ["service_role"] - scopes: ["calendar_read", "calendar_edit"] - # Define ABAC rules for the Upper method - abac: - scopes: ["calendar_read", "calendar_edit"] - time: - time-of-day: - - from: "08:15:00" - to: "12:00:00" - - from: "12:30" - to: "17:30" - days-of-week: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"] - policy-validator: - statement: "${env.time.year >= 2017}" diff --git a/examples/grpc/security-abac/src/main/resources/logging.properties b/examples/grpc/security-abac/src/main/resources/logging.properties deleted file mode 100644 index 94c6fdd77e2..00000000000 --- a/examples/grpc/security-abac/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -.level=INFO -AUDIT.level=FINEST diff --git a/examples/grpc/security-outbound/README.md b/examples/grpc/security-outbound/README.md deleted file mode 100644 index 5c1c215720f..00000000000 --- a/examples/grpc/security-outbound/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon gRPC Security ABAC Example - -An example gRPC outbound security - -## Build and run - -```bash -mvn -f ../pom.xml -pl common,security-outbound package -java -jar target/helidon-examples-grpc-security-outbound.jar -``` - -Exercise the example: -```bash -java -cp target/helidon-examples-grpc-security-outbound.jar \ - io.helidon.grpc.examples.security.outbound.SecureGreetClient -``` - -Sample output of the client: -```bash -bob -Greeting set to: MERHABA -bob -``` diff --git a/examples/grpc/security-outbound/pom.xml b/examples/grpc/security-outbound/pom.xml deleted file mode 100644 index 43b2e91ced7..00000000000 --- a/examples/grpc/security-outbound/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-security-outbound - Helidon gRPC Server Examples Outbound Security - - - Examples of outbound security when using gRPC services - - - - io.helidon.grpc.examples.security.outbound.SecureServer - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.grpc - helidon-grpc-core - - - io.helidon.grpc - helidon-grpc-server - - - io.helidon.security.integration - helidon-security-integration-grpc - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.bundles - helidon-bundles-webserver - - - io.helidon.security.integration - helidon-security-integration-jersey-client - - - io.helidon.bundles - helidon-bundles-security - - - io.helidon.grpc - helidon-grpc-client - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-security - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureGreetClient.java b/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureGreetClient.java deleted file mode 100644 index 4e3b00a8440..00000000000 --- a/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureGreetClient.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security.outbound; - - -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.Greet; -import io.helidon.grpc.examples.common.GreetServiceGrpc; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.integration.grpc.GrpcClientSecurity; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; - -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; - -/** - * A GreetService client that uses {@link io.grpc.CallCredentials} using basic auth. - */ -public class SecureGreetClient { - - private SecureGreetClient() { - } - - /** - * Program entry point. - * - * @param args program arguments - */ - public static void main(String[] args) { - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - Config config = Config.create(); - - // configure Helidon security and add the basic auth provider - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.create(config.get("http-basic-auth"))) - .build(); - - // create the gRPC client security call credentials - // setting the properties used by the basic auth provider for user name and password - GrpcClientSecurity clientSecurity = GrpcClientSecurity.builder(security.createContext("test.client")) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "Bob") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "password") - .build(); - - // create the GreetService client stub and use the GrpcClientSecurity call credentials - GreetServiceGrpc.GreetServiceBlockingStub stub = GreetServiceGrpc.newBlockingStub(channel) - .withCallCredentials(clientSecurity); - - Greet.GreetResponse greetResponse = stub.greet(Greet.GreetRequest.newBuilder().setName("Bob").build()); - - System.out.println(greetResponse.getMessage()); - - Greet.SetGreetingResponse setGreetingResponse = - stub.setGreeting(Greet.SetGreetingRequest.newBuilder().setGreeting("Merhaba").build()); - - System.out.println("Greeting set to: " + setGreetingResponse.getGreeting()); - - greetResponse = stub.greet(Greet.GreetRequest.newBuilder().setName("Bob").build()); - - System.out.println(greetResponse.getMessage()); - } -} diff --git a/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureServer.java b/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureServer.java deleted file mode 100644 index 2c54640521a..00000000000 --- a/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/SecureServer.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security.outbound; - -import java.util.Optional; - -import io.helidon.common.LogConfig; -import io.helidon.common.context.Context; -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.grpc.core.GrpcHelper; -import io.helidon.grpc.examples.common.Greet; -import io.helidon.grpc.examples.common.StringService; -import io.helidon.grpc.examples.common.StringServiceGrpc; -import io.helidon.grpc.examples.common.Strings; -import io.helidon.grpc.server.GrpcRouting; -import io.helidon.grpc.server.GrpcServer; -import io.helidon.grpc.server.GrpcServerConfiguration; -import io.helidon.grpc.server.GrpcService; -import io.helidon.grpc.server.ServiceDescriptor; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.integration.grpc.GrpcClientSecurity; -import io.helidon.security.integration.grpc.GrpcSecurity; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; -import io.helidon.webserver.WebServer; - -import io.grpc.Channel; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; - -import static io.helidon.grpc.core.ResponseHelper.complete; - -/** - * An example server that configures services with outbound security. - */ -public class SecureServer { - - private static GrpcServer grpcServer; - - private static WebServer webServer; - - private SecureServer() { - } - - /** - * Program entry point. - * - * @param args the program command line arguments - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Config config = Config.create(); - - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.create(config.get("http-basic-auth"))) - .build(); - - grpcServer = createGrpcServer(config.get("grpc"), security); - webServer = createWebServer(config.get("webserver"), security); - } - - /** - * Create the gRPC server. - */ - private static GrpcServer createGrpcServer(Config config, Security security) { - - GrpcRouting grpcRouting = GrpcRouting.builder() - // Add the security interceptor with a default of allowing any authenticated user - .intercept(GrpcSecurity.create(security).securityDefaults(GrpcSecurity.authenticate())) - // add the StringService with required role "admin" - .register(new StringService(), GrpcSecurity.rolesAllowed("admin")) - // add the GreetService (picking up the default security of any authenticated user) - .register(new GreetService()) - .build(); - - GrpcServer grpcServer = GrpcServer.create(GrpcServerConfiguration.create(config), grpcRouting); - - grpcServer.start() - .thenAccept(s -> { - System.out.println("gRPC server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("gRPC server startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - return grpcServer; - } - - /** - * Create the web server. - */ - private static WebServer createWebServer(Config config, Security security) { - - Routing routing = Routing.builder() - .register(WebSecurity.create(security).securityDefaults(WebSecurity.authenticate())) - .register(new RestService()) - .build(); - - WebServer webServer = WebServer.create(routing, config); - - webServer.start() - .thenAccept(s -> { - System.out.println("Web server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Web server startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - return webServer; - } - - /** - * A gRPC greet service that uses outbound security to - * access a ReST API. - */ - public static class GreetService - implements GrpcService { - - /** - * The current greeting. - */ - private String greeting = "hello"; - - /** - * The Helidon WebClient to use to make ReST calls. - */ - private WebClient client; - - private GreetService() { - client = WebClient.builder() - .addService(WebClientSecurity.create()) - .build(); - } - - @Override - public void update(ServiceDescriptor.Rules rules) { - rules.proto(Greet.getDescriptor()) - .unary("Greet", this::greet) - .unary("SetGreeting", this::setGreeting); - } - - /** - * This method calls a secure ReST endpoint using the caller's credentials. - * - * @param request the request - * @param observer the observer to send the response to - */ - private void greet(Greet.GreetRequest request, StreamObserver observer) { - // Obtain the greeting name from the request (default to "World". - String name = Optional.ofNullable(request.getName()).orElse("World"); - - // Obtain the security context from the current gRPC context - SecurityContext securityContext = GrpcSecurity.SECURITY_CONTEXT.get(); - Context context = Context.builder().id("example").build(); - context.register(securityContext); - - // Use the current credentials call the "lower" ReST endpoint which will call - // the "Lower" method on the secure gRPC StringService. - client.get() - .uri("http://localhost:" + webServer.port()) - .path("lower") - .queryParam("value", name) - .context(context) - .request() - .thenAccept(it -> handleResponse(it, observer)) - .exceptionally(throwable -> { - observer.onError(throwable); - return null; - }); - } - - /** - * This method calls a secure ReST endpoint overriding the caller's credentials and - * using the admin user's credentials. - * - * @param request the request - * @param observer the observer to send the response to - */ - private void setGreeting(Greet.SetGreetingRequest request, StreamObserver observer) { - // Obtain the greeting name from the request (default to "hello". - String name = Optional.ofNullable(request.getGreeting()).orElse("hello"); - - // Obtain the security context from the current gRPC context - SecurityContext securityContext = GrpcSecurity.SECURITY_CONTEXT.get(); - Context context = Context.builder().id("example").build(); - context.register(securityContext); - - // Use the admin user's credentials call the "upper" ReST endpoint which will call - // the "Upper" method on the secure gRPC StringService. - client.get() - .uri("http://127.0.0.1:" + webServer.port()) - .path("upper") - .queryParam("value", name) - .context(context) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "Ted") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "secret") - .request() - .thenAccept(it -> handleResponse(it, observer)) - .exceptionally(throwable -> { - observer.onError(throwable); - return null; - }); - } - - private void handleResponse(WebClientResponse response, StreamObserver observer) { - if (response.status() == Http.Status.OK_200) { - // Send the response to the caller of the current greeting and lower case name - response.content() - .as(String.class) - .thenAccept(str -> complete(observer, - Greet.SetGreetingResponse.newBuilder().setGreeting(str).build())); - } else { - completeWithError(response, observer); - } - } - - private void completeWithError(WebClientResponse response, StreamObserver observer) { - Http.ResponseStatus status = response.status(); - - if (status == Http.Status.UNAUTHORIZED_401 - || status == Http.Status.FORBIDDEN_403){ - observer.onError(Status.PERMISSION_DENIED.asRuntimeException()); - } else { - response.content() - .as(String.class) - .thenAccept(str -> observer.onError(Status.INTERNAL.withDescription(str).asRuntimeException())); - } - } - - @Override - public String name() { - return "GreetService"; - } - } - - /** - * A ReST service that calls the gRPC StringService to mutate String values. - */ - public static class RestService - implements Service { - - private Channel channel; - - @Override - public void update(Routing.Rules rules) { - rules.get("/lower", WebSecurity.rolesAllowed("user"), this::lower) - .get("/upper", WebSecurity.rolesAllowed("user"), this::upper); - } - - /** - * Call the gRPC StringService Lower method overriding the caller's credentials and - * using the admin user's credentials. - * - * @param req the http request - * @param res the http response - */ - private void lower(ServerRequest req, ServerResponse res) { - try { - // Create the gRPC client security credentials from the current request - // overriding with the admin user's credentials - GrpcClientSecurity clientSecurity = GrpcClientSecurity.builder(req) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "Ted") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "secret") - .build(); - - StringServiceGrpc.StringServiceBlockingStub stub = StringServiceGrpc.newBlockingStub(ensureChannel()) - .withCallCredentials(clientSecurity); - - String value = req.queryParams().first("value").orElse(null); - Strings.StringMessage response = stub.lower(Strings.StringMessage.newBuilder().setText(value).build()); - - res.status(200).send(response.getText()); - } catch (StatusRuntimeException e) { - res.status(GrpcHelper.toHttpResponseStatus(e.getStatus())).send(); - } - } - - /** - * Call the gRPC StringService Upper method using the current caller's credentials. - * - * @param req the http request - * @param res the http response - */ - private void upper(ServerRequest req, ServerResponse res) { - try { - // Create the gRPC client security credentials from the current request - GrpcClientSecurity clientSecurity = GrpcClientSecurity.create(req); - - StringServiceGrpc.StringServiceBlockingStub stub = StringServiceGrpc.newBlockingStub(ensureChannel()) - .withCallCredentials(clientSecurity); - - String value = req.queryParams().first("value").orElse(null); - Strings.StringMessage response = stub.upper(Strings.StringMessage.newBuilder().setText(value).build()); - - res.status(200).send(response.getText()); - } catch (StatusRuntimeException e) { - res.status(GrpcHelper.toHttpResponseStatus(e.getStatus())).send(); - } - } - - private synchronized Channel ensureChannel() { - if (channel == null) { - channel = InProcessChannelBuilder.forName(grpcServer.configuration().name()).build(); - } - return channel; - } - } -} diff --git a/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/package-info.java b/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/package-info.java deleted file mode 100644 index 3278ed34df9..00000000000 --- a/examples/grpc/security-outbound/src/main/java/io/helidon/grpc/examples/security/outbound/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Examples of using outbound security with gRPC services. - */ -package io.helidon.grpc.examples.security.outbound; diff --git a/examples/grpc/security-outbound/src/main/resources/application.yaml b/examples/grpc/security-outbound/src/main/resources/application.yaml deleted file mode 100644 index ed8a83c72ac..00000000000 --- a/examples/grpc/security-outbound/src/main/resources/application.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# -# 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. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -grpc: - name: "test.server" - port: 1408 - -webserver: - port: 8080 - -http-basic-auth: - users: - - login: "Ted" - password: "secret" - roles: ["user", "admin"] - - login: "Bob" - password: "password" - roles: ["user"] - outbound: - - name: propagate_all diff --git a/examples/grpc/security-outbound/src/main/resources/logging.properties b/examples/grpc/security-outbound/src/main/resources/logging.properties deleted file mode 100644 index c970479a0ae..00000000000 --- a/examples/grpc/security-outbound/src/main/resources/logging.properties +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -AUDIT.level=FINEST -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/grpc/security/README.md b/examples/grpc/security/README.md deleted file mode 100644 index a1aa4ccc7d4..00000000000 --- a/examples/grpc/security/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Helidon gRPC Security Example - -An example gRPC server using basic auth security. - -## Build and run - -```bash -mvn -f ../pom.xml -pl common,security package -java -jar target/helidon-examples-grpc-security.jar -``` - -# Exercise the example: -```bash -java -cp target/helidon-examples-grpc-security.jar \ - io.helidon.grpc.examples.security.SecureGreetClient -java -cp target/helidon-examples-grpc-security.jar \ - io.helidon.grpc.examples.security.SecureStringClient -``` - -# Sample client output: -SecureGreetClient: -```bash -message: "Hello Aleks!" - -greeting: "Hey" - -message: "Hey Aleks!" -``` - -SecureStringClient: -```bash -Response from Lower method call is 'abcde' -``` diff --git a/examples/grpc/security/pom.xml b/examples/grpc/security/pom.xml deleted file mode 100644 index 81e362a3a83..00000000000 --- a/examples/grpc/security/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.grpc - helidon-examples-grpc-security - Helidon gRPC Server Examples Security - - - Examples of securing gRPC services - - - - io.helidon.grpc.examples.security.SecureServer - - - - - io.helidon.examples.grpc - helidon-examples-grpc-common - ${project.version} - - - io.helidon.grpc - helidon-grpc-core - - - io.helidon.grpc - helidon-grpc-server - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.security.integration - helidon-security-integration-grpc - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.grpc - helidon-grpc-client - - - io.grpc - grpc-netty - - - io.grpc - grpc-services - - - io.grpc - grpc-protobuf - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureGreetClient.java b/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureGreetClient.java deleted file mode 100644 index a6e5e6ca1fe..00000000000 --- a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureGreetClient.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security; - -import io.helidon.config.Config; -import io.helidon.grpc.client.ClientServiceDescriptor; -import io.helidon.grpc.client.GrpcServiceClient; -import io.helidon.grpc.examples.common.Greet; -import io.helidon.grpc.examples.common.GreetServiceGrpc; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.integration.grpc.GrpcClientSecurity; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; - -import io.grpc.CallCredentials; -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; - -/** - * A {@link io.helidon.grpc.examples.common.GreetService} client that optionally - * provides {@link CallCredentials} using basic auth. - */ -public class SecureGreetClient { - - private SecureGreetClient() { - } - - /** - * Main entry point. - * - * @param args the program arguments - {@code arg[0]} is the user name - * and {@code arg[1] is the password} - */ - public static void main(String[] args) { - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - // Obtain the user name and password from the program arguments - String user = args.length >= 2 ? args[0] : "Ted"; - String password = args.length >= 2 ? args[1] : "secret"; - - Config config = Config.create(); - - // configure Helidon security and add the basic auth provider - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.create(config.get("http-basic-auth"))) - .build(); - - // create the gRPC client security call credentials - // setting the properties used by the basic auth provider for user name and password - GrpcClientSecurity clientSecurity = GrpcClientSecurity.builder(security.createContext("test.client")) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, user) - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, password) - .build(); - - // Create the client service descriptor and add the call credentials - ClientServiceDescriptor descriptor = ClientServiceDescriptor - .builder(GreetServiceGrpc.getServiceDescriptor()) - .callCredentials(clientSecurity) - .build(); - - // create the client for the service - GrpcServiceClient client = GrpcServiceClient.create(channel, descriptor); - - greet(client); - setGreeting(client); - greet(client); - } - - private static void greet(GrpcServiceClient client) { - try { - Greet.GreetRequest request = Greet.GreetRequest.newBuilder().setName("Aleks").build(); - Greet.GreetResponse response = client.blockingUnary("Greet", request); - - System.out.println(response); - } catch (Exception e) { - System.err.println("Caught exception obtaining greeting: " + e.getMessage()); - } - } - - private static void setGreeting(GrpcServiceClient client) { - try { - Greet.SetGreetingRequest setRequest = Greet.SetGreetingRequest.newBuilder().setGreeting("Hey").build(); - Greet.SetGreetingResponse setResponse = client.blockingUnary("SetGreeting", setRequest); - - System.out.println(setResponse); - } catch (Exception e) { - System.err.println("Caught exception setting greeting: " + e.getMessage()); - } - } -} diff --git a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureServer.java b/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureServer.java deleted file mode 100644 index 1bf9f84a627..00000000000 --- a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureServer.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.grpc.examples.common.GreetService; -import io.helidon.grpc.examples.common.StringService; -import io.helidon.grpc.server.GrpcRouting; -import io.helidon.grpc.server.GrpcServer; -import io.helidon.grpc.server.GrpcServerConfiguration; -import io.helidon.grpc.server.ServiceDescriptor; -import io.helidon.security.Security; -import io.helidon.security.integration.grpc.GrpcSecurity; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; - -/** - * An example of a secure gRPC server. - */ -public class SecureServer { - - private SecureServer() { - } - - /** - * Main entry point. - * - * @param args the program arguments - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Config config = Config.create(); - - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.create(config.get("http-basic-auth"))) - .build(); - - ServiceDescriptor greetService1 = ServiceDescriptor.builder(new GreetService(config)) - .name("GreetService") - .intercept(GrpcSecurity.rolesAllowed("user")) - .intercept("SetGreeting", GrpcSecurity.rolesAllowed("admin")) - .build(); - - GrpcRouting grpcRouting = GrpcRouting.builder() - .intercept(GrpcSecurity.create(security).securityDefaults(GrpcSecurity.authenticate())) - .register(greetService1) - .register(new StringService()) - .build(); - - GrpcServerConfiguration serverConfig = GrpcServerConfiguration.create(config.get("grpc")); - GrpcServer grpcServer = GrpcServer.create(serverConfig, grpcRouting); - - grpcServer.start() - .thenAccept(s -> { - System.out.println("gRPC server is UP! http://localhost:" + s.port()); - s.whenShutdown().thenRun(() -> System.out.println("gRPC server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - } -} diff --git a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureStringClient.java b/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureStringClient.java deleted file mode 100644 index 0c58e3a0537..00000000000 --- a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/SecureStringClient.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.grpc.examples.security; - - -import io.helidon.config.Config; -import io.helidon.grpc.client.ClientServiceDescriptor; -import io.helidon.grpc.client.GrpcServiceClient; -import io.helidon.grpc.examples.common.StringServiceGrpc; -import io.helidon.grpc.examples.common.Strings; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.integration.grpc.GrpcClientSecurity; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; - -import io.grpc.CallCredentials; -import io.grpc.Channel; -import io.grpc.ManagedChannelBuilder; - -/** - * A {@link io.helidon.grpc.examples.common.StringService} client that optionally - * provides {@link CallCredentials} using basic auth. - */ -public class SecureStringClient { - - private SecureStringClient() { - } - - /** - * Program entry point. - * - * @param args the program arguments - {@code arg[0]} is the user name - * and {@code arg[1] is the password} - */ - public static void main(String[] args) { - Channel channel = ManagedChannelBuilder.forAddress("localhost", 1408) - .usePlaintext() - .build(); - - // Obtain the user name and password from the program arguments - String user = args.length >= 2 ? args[0] : "Ted"; - String password = args.length >= 2 ? args[1] : "secret"; - - Config config = Config.create(); - - // configure Helidon security and add the basic auth provider - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.create(config.get("http-basic-auth"))) - .build(); - - // create the gRPC client security call credentials - // setting the properties used by the basic auth provider for user name and password - GrpcClientSecurity clientSecurity = GrpcClientSecurity.builder(security.createContext("test.client")) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, user) - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, password) - .build(); - - // Create the client service descriptor and add the call credentials - ClientServiceDescriptor descriptor = ClientServiceDescriptor - .builder(StringServiceGrpc.getServiceDescriptor()) - .callCredentials(clientSecurity) - .build(); - - // create the client for the service - GrpcServiceClient client = GrpcServiceClient.create(channel, descriptor); - - Strings.StringMessage request = Strings.StringMessage.newBuilder().setText("ABCDE").build(); - Strings.StringMessage response = client.blockingUnary("Lower", request); - - System.out.println("Response from Lower method call is '" + response.getText() + "'"); - } -} diff --git a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/package-info.java b/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/package-info.java deleted file mode 100644 index fbc9819e860..00000000000 --- a/examples/grpc/security/src/main/java/io/helidon/grpc/examples/security/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A set of small usage examples. Start with {@link io.helidon.grpc.examples.security.SecureServer Main} class. - */ -package io.helidon.grpc.examples.security; diff --git a/examples/grpc/security/src/main/resources/application.yaml b/examples/grpc/security/src/main/resources/application.yaml deleted file mode 100644 index 9accccc7c83..00000000000 --- a/examples/grpc/security/src/main/resources/application.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# -# 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. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -grpc: - name: "test.server" - port: 1408 - -webserver: - port: 8080 - -http-basic-auth: - users: - - login: "Ted" - password: "secret" - roles: ["user", "admin"] - - login: "Bob" - password: "password" - roles: ["user"] diff --git a/examples/grpc/security/src/main/resources/logging.properties b/examples/grpc/security/src/main/resources/logging.properties deleted file mode 100644 index c970479a0ae..00000000000 --- a/examples/grpc/security/src/main/resources/logging.properties +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -AUDIT.level=FINEST -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/health/basics/README.md b/examples/health/basics/README.md deleted file mode 100644 index bca6a94a541..00000000000 --- a/examples/health/basics/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon Health Basic Example - -This example shows the basics of using Helidon SE Health. It uses the -set of built-in health checks that Helidon provides plus defines a -custom health check. - -## Build and run - -Start the application: - -```bash -mvn package -java -jar target/helidon-examples-health-basics.jar -``` - -Note the port number reported by the application. - -Probe the health endpoints: - -```bash -curl -X GET http://localhost:PORT/health/ -curl -X GET http://localhost:PORT/health/ready - diff --git a/examples/health/basics/pom.xml b/examples/health/basics/pom.xml deleted file mode 100644 index f5841b56ea3..00000000000 --- a/examples/health/basics/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.health - helidon-examples-health-basics - Helidon Health Examples Basics - - - Basic usage of health checks in helidon SE - - - - io.helidon.examples.health.basics.Main - - - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.webserver - helidon-webserver - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/Main.java b/examples/health/basics/src/main/java/io/helidon/examples/health/basics/Main.java deleted file mode 100644 index 2c180c1e553..00000000000 --- a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/Main.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.health.basics; - -import java.time.Duration; - -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import org.eclipse.microprofile.health.HealthCheckResponse; - -/** - * Main class of health check integration example. - */ -public final class Main { - - private static long serverStartTime; - - private Main() { - } - - /** - * Start the example. Prints endpoints to standard output. - * - * @param args not used - */ - public static void main(String[] args) { - serverStartTime = System.currentTimeMillis(); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) - .addReadiness(() -> HealthCheckResponse.named("exampleHealthCheck") - .up() - .withData("time", System.currentTimeMillis()) - .build()) - .addStartup(() -> HealthCheckResponse.named("exampleStartCheck") - .status(isStarted()) - .withData("time", System.currentTimeMillis()) - .build()) - .build(); - - Routing routing = Routing.builder() - .register(health) - .get("/hello", (req, res) -> res.send("Hello World!")) - .build(); - - WebServer ws = WebServer.create(routing); - - ws.start() - .thenApply(webServer -> { - String endpoint = "http://localhost:" + webServer.port(); - System.out.println("Hello World started on " + endpoint + "/hello"); - System.out.println("Health checks available on " + endpoint + "/health"); - return null; - }); - - } - - private static boolean isStarted() { - return Duration.ofMillis(System.currentTimeMillis() - serverStartTime).getSeconds() >= 8; - } -} diff --git a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/package-info.java b/examples/health/basics/src/main/java/io/helidon/examples/health/basics/package-info.java deleted file mode 100644 index 52d9f57601a..00000000000 --- a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Example of healthchecks in helidon SE. - */ -package io.helidon.examples.health.basics; diff --git a/examples/health/pom.xml b/examples/health/pom.xml deleted file mode 100644 index b60b2b5f98b..00000000000 --- a/examples/health/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - 4.0.0 - - helidon-examples-project - io.helidon.examples - 3.2.7-SNAPSHOT - - io.helidon.examples.health - helidon-examples-health-project - pom - Helidon Health Examples - - - basics - - diff --git a/examples/integrations/README.md b/examples/integrations/README.md deleted file mode 100644 index 05fd10c9d0c..00000000000 --- a/examples/integrations/README.md +++ /dev/null @@ -1 +0,0 @@ -# Helidon Integrations Examples diff --git a/examples/integrations/cdi/README.md b/examples/integrations/cdi/README.md deleted file mode 100644 index 64fad79554a..00000000000 --- a/examples/integrations/cdi/README.md +++ /dev/null @@ -1 +0,0 @@ -# Helidon Integrations CDI Examples diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/README.md b/examples/integrations/cdi/datasource-hikaricp-h2/README.md deleted file mode 100644 index 31b6042c9d7..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# H2 Integration Example - -## Overview - -This example shows a trivial Helidon MicroProfile application that -uses the Hikari connection pool CDI integration and an H2 in-memory -database. - -## Build and run - -```bash -mvn package -java -jar target/helidon-integrations-examples-datasource-hikaricp-h2.jar -``` - -Try the endpoint: -```bash -curl http://localhost:8080/tables -``` diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/pom.xml b/examples/integrations/cdi/datasource-hikaricp-h2/pom.xml deleted file mode 100644 index d12ec7b0691..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-integrations-examples-datasource-hikaricp-h2 - Helidon CDI Extensions Examples DataSource/HikariCP H2 - - - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - org.eclipse.microprofile.config - microprofile-config-api - compile - - - - - com.h2database - h2 - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - org.jboss - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java b/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java deleted file mode 100644 index 76c6d33acba..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.integrations.examples.datasource.hikaricp.jaxrs; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; - -import javax.sql.DataSource; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * A JAX-RS resource class in {@linkplain ApplicationScoped - * application scope} rooted at {@code /tables}. - * - * @see #get() - */ -@Path("/tables") -@ApplicationScoped -public class TablesResource { - - private final DataSource dataSource; - - /** - * Creates a new {@link TablesResource}. - * - * @param dataSource the {@link DataSource} to use to acquire - * database table names; must not be {@code null} - * - * @exception NullPointerException if {@code dataSource} is {@code - * null} - */ - @Inject - public TablesResource(@Named("example") final DataSource dataSource) { - super(); - this.dataSource = Objects.requireNonNull(dataSource); - } - - /** - * Returns a {@link Response} which, if successful, contains a - * newline-separated list of Oracle database table names. - * - *

This method never returns {@code null}.

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

This method never returns {@code null}.

- * - * @return a non-{@code null} {@link Response} - * - * @exception SQLException if a database error occurs - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public Response get() throws SQLException { - final StringBuilder sb = new StringBuilder(); - try (Connection connection = this.dataSource.getConnection(); - PreparedStatement ps = - connection.prepareStatement(" SELECT TABLE_NAME" - + " FROM INFORMATION_SCHEMA.TABLES " - + "ORDER BY TABLE_NAME ASC"); - ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - sb.append(rs.getString(1)).append("\n"); - } - } - final Response returnValue = Response.ok() - .entity(sb.toString()) - .build(); - return returnValue; - } - -} diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java b/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java deleted file mode 100644 index 5814f096ad2..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Provides JAX-RS-related classes and interfaces for this example - * project. - */ -package io.helidon.integrations.examples.datasource.hikaricp.jaxrs; diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 32edc282315..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Default database properties. -javax.sql.DataSource.example.dataSourceClassName=com.mysql.cj.jdbc.MysqlDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:mysql://localhost:3306 -javax.sql.DataSource.example.dataSource.user = root -javax.sql.DataSource.example.dataSource.password = tiger - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/datasource-hikaricp/.dockerignore b/examples/integrations/cdi/datasource-hikaricp/.dockerignore deleted file mode 100644 index 2f7896d1d13..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/examples/integrations/cdi/datasource-hikaricp/Dockerfile b/examples/integrations/cdi/datasource-hikaricp/Dockerfile deleted file mode 100644 index 13dcb075d73..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-integrations-datasource-hikaricp.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD [ "java", "-jar", "helidon-examples-integrations-datasource-hikaricp.jar" ] - -EXPOSE 8080 diff --git a/examples/integrations/cdi/datasource-hikaricp/README.md b/examples/integrations/cdi/datasource-hikaricp/README.md deleted file mode 100644 index 7a54e43ff57..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# Hikari Connection Pool Integration Example - -## Overview - -This example shows a trivial Helidon MicroProfile application that -uses the Hikari connection pool CDI integration. It also shows how to -run the Oracle database in a Docker container and connect the -application to it. - -## Prerequisites - -You'll need an Oracle account in order to log in to the Oracle -Container Registry. The Oracle Container Registry is where the Docker -image housing the Oracle database is located. To set up an Oracle -account if you don't already have one, see -[the Oracle account creation website](https://profile.oracle.com/myprofile/account/create-account.jspx). - -## Notes - -To log in to the Oracle Container Registry (which you will need to do -in order to download Oracle database Docker images from it): - -```bash -docker login -u username -p password container-registry.oracle.com -``` - -For more information on the Oracle Container Registry, please visit -its [website](https://container-registry.oracle.com/). - -To run Oracle's `database/standard` Docker image in a Docker container -named `oracle` that publishes ports 1521 and 5500 to -the host while relying on the defaults for all other settings: - -```bash -docker container run -d -it -p 1521:1521 -p 5500:5500 --shm-size=3g \ - --name oracle \ - container-registry.oracle.com/database/standard:latest -``` - -It will take about ten minutes before the database is ready. - -For more information on the Oracle database image used by this -example, you can visit the relevant section of the - [Oracle Container Registry website](https://container-registry.oracle.com/). - -To ensure that the sample application is configured to talk to the -Oracle database running in this Docker container, verify that the -following lines (among others) are present in -`src/main/resources/META-INF/microprofile-config.properties`: - -```properties -javax.sql.DataSource.example.dataSourceClassName=oracle.jdbc.pool.OracleDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:oracle:thin:@localhost:1521:ORCL -javax.sql.DataSource.example.dataSource.user = sys as sysoper -javax.sql.DataSource.example.dataSource.password = Oracle -``` - -## Build and run - -With Docker: -```bash -docker build -t helidon-examples-integrations-datasource-hikaricp . -docker run --rm -d \ - --link oracle \ - -e javax_sql_DataSource_example_dataSource_url="jdbc:oracle:thin:@oracle:1521:ORCL" \ - --name helidon-examples-integrations-datasource-hikaricp \ - -p 8080:8080 helidon-examples-integrations-datasource-hikaricp:latest -``` -OR - -With Maven: -```bash -mvn package -java -jar target/helidon-examples-integrations-datasource-hikaricp.jar -``` - -Try the endpoint: -```bash -curl http://localhost:8080/tables -``` - -Stop the docker containers: -```bash -docker stop oracle helidon-examples-integrations-datasource-hikaricp -``` diff --git a/examples/integrations/cdi/datasource-hikaricp/pom.xml b/examples/integrations/cdi/datasource-hikaricp/pom.xml deleted file mode 100644 index 2882152b039..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/pom.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-examples-integrations-datasource-hikaricp - Helidon CDI Extensions Examples DataSource/HikariCP - - - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - redis.clients - jedis - compile - - - org.eclipse.microprofile.config - microprofile-config-api - compile - - - - - io.helidon.integrations.db - ojdbc - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - org.jboss - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java b/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java deleted file mode 100644 index a8a9b5bd2d0..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/TablesResource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.integrations.examples.datasource.hikaricp.jaxrs; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; - -import javax.sql.DataSource; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * A JAX-RS resource class in {@linkplain ApplicationScoped - * application scope} rooted at {@code /tables}. - * - * @see #get() - */ -@Path("/tables") -@ApplicationScoped -public class TablesResource { - - private final DataSource dataSource; - - /** - * Creates a new {@link TablesResource}. - * - * @param dataSource the {@link DataSource} to use to acquire - * database table names; must not be {@code null} - * - * @exception NullPointerException if {@code dataSource} is {@code - * null} - */ - @Inject - public TablesResource(@Named("example") final DataSource dataSource) { - super(); - this.dataSource = Objects.requireNonNull(dataSource); - } - - /** - * Returns a {@link Response} which, if successful, contains a - * newline-separated list of Oracle database table names. - * - *

This method never returns {@code null}.

- * - * @return a non-{@code null} {@link Response} - * - * @exception SQLException if a database error occurs - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public Response get() throws SQLException { - final StringBuilder sb = new StringBuilder(); - try (Connection connection = this.dataSource.getConnection(); - PreparedStatement ps = - connection.prepareStatement(" SELECT TABLE_NAME" - + " FROM ALL_TABLES " - + "ORDER BY TABLE_NAME ASC"); - ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - sb.append(rs.getString(1)).append("\n"); - } - } - final Response returnValue = Response.ok() - .entity(sb.toString()) - .build(); - return returnValue; - } - -} diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java b/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java deleted file mode 100644 index 2b4f85b6e0f..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/integrations/examples/datasource/hikaricp/jaxrs/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Provides JAX-RS-related classes and interfaces for this example - * project. - */ -package io.helidon.integrations.examples.datasource.hikaricp.jaxrs; diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 1140dcc0511..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Default database properties. -# See -# https://container-registry.oracle.com/pls/apex/f?p=113:4:102624334361221::NO::: -# and -# https://technology.amis.nl/2017/11/18/run-oracle-database-in-docker-using-prebaked-image-from-oracle-container-registry-a-two-minute-guide/ -javax.sql.DataSource.example.dataSourceClassName=oracle.jdbc.pool.OracleDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:oracle:thin:@localhost:1521:ORCL -javax.sql.DataSource.example.dataSource.user = sys as sysoper -javax.sql.DataSource.example.dataSource.password = Oracle - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/jedis/.dockerignore b/examples/integrations/cdi/jedis/.dockerignore deleted file mode 100644 index 2f7896d1d13..00000000000 --- a/examples/integrations/cdi/jedis/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/examples/integrations/cdi/jedis/Dockerfile b/examples/integrations/cdi/jedis/Dockerfile deleted file mode 100644 index 64a2a051409..00000000000 --- a/examples/integrations/cdi/jedis/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-integrations-cdi-jedis.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD [ "java", "-jar", "helidon-examples-integrations-cdi-jedis.jar" ] - -EXPOSE 8080 diff --git a/examples/integrations/cdi/jedis/README.md b/examples/integrations/cdi/jedis/README.md deleted file mode 100644 index 51311df18e2..00000000000 --- a/examples/integrations/cdi/jedis/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Jedis Integration Example - -## Start Redis - -```bash -docker run --rm --name redis -d -p 6379:6379 redis -``` - -## Build and run - -With Docker: -```bash -docker build -t helidon-examples-integrations-cdi-jedis . -docker run --rm -d \ - --link redis - --name helidon-examples-integrations-cdi-jedis \ - -p 8080:8080 helidon-examples-integrations-cdi-jedis:latest -``` - -With Java: -```bash -mvn package -java -jar target/helidon-examples-integrations-cdi-jedis.jar -``` - -Try the endpoint: -```bash -curl -X PUT -H "Content-Type: text/plain" http://localhost:8080/jedis/foo -d 'bar' -curl http://localhost:8080/jedis/foo -``` - -## Run with Kubernetes (docker for desktop) - -```bash -docker build -t helidon-examples-integrations-cdi-jedis . -kubectl apply \ - -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/ingress-nginx-3.15.2/deploy/static/provider/cloud/deploy.yaml \ - -f app.yaml -``` - -Try the endpoint: -```bash -curl -X PUT -H "Content-Type: text/plain" http://localhost/helidon-cdi-jedis/jedis/foo -d 'bar' -curl http://localhost/helidon-cdi-jedis/jedis/foo -``` - -Stop the docker containers: -```bash -docker stop redis helidon-examples-integrations-cdi-jedis -``` - -Delete the Kubernetes resources: -```bash -kubectl delete -f app.yaml -``` diff --git a/examples/integrations/cdi/jedis/app.yaml b/examples/integrations/cdi/jedis/app.yaml deleted file mode 100644 index 3f812ae47ea..00000000000 --- a/examples/integrations/cdi/jedis/app.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-examples-integrations-cdi-jedis - labels: - app: helidon-examples-integrations-cdi-jedis - version: v1 -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-integrations-cdi-jedis - spec: - containers: - - name: helidon-examples-integrations-cdi-jedis - image: helidon-examples-integrations-cdi-jedis - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 - env: - - name: redis_clients_jedis_JedisPool_default_host - value: redis - ---- - -kind: Service -apiVersion: v1 -metadata: - name: helidon-examples-integrations-cdi-jedis - labels: - app: helidon-examples-integrations-cdi-jedis -spec: - type: ClusterIP - ports: - - name: http - port: 8080 - selector: - app: helidon-examples-integrations-cdi-jedis - sessionAffinity: None - ---- - -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: helidon-examples-integrations-cdi-jedis - annotations: - nginx.ingress.kubernetes.io/rewrite-target: /$1 -spec: - rules: - - host: localhost - http: - paths: - - path: /helidon-cdi-jedis/(.*) - pathType: Prefix - backend: - service: - name: helidon-examples-integrations-cdi-jedis - port: - number: 8080 diff --git a/examples/integrations/cdi/jedis/pom.xml b/examples/integrations/cdi/jedis/pom.xml deleted file mode 100644 index 8b5688ddd5e..00000000000 --- a/examples/integrations/cdi/jedis/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-examples-integrations-cdi-jedis - Helidon CDI Extensions Examples Jedis - - - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - redis.clients - jedis - compile - - - org.eclipse.microprofile.config - microprofile-config-api - compile - - - - - io.helidon.integrations.cdi - helidon-integrations-cdi-jedis - runtime - - - org.jboss - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/cdi/jedis/redis.yaml b/examples/integrations/cdi/jedis/redis.yaml deleted file mode 100644 index f32f946040a..00000000000 --- a/examples/integrations/cdi/jedis/redis.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: redis -spec: - type: ClusterIP - selector: - app: redis - ports: - - name: tcp - port: 6379 - targetPort: 6379 - ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: redis - labels: - app: redis -spec: - replicas: 1 - template: - metadata: - labels: - app: redis - spec: - containers: - - name: redis - image: redis:5 - imagePullPolicy: IfNotPresent - ports: - - containerPort: 6379 diff --git a/examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/RedisClientResource.java b/examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/RedisClientResource.java deleted file mode 100644 index 49d2143bf42..00000000000 --- a/examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/RedisClientResource.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.integrations.examples.jedis.jaxrs; - -import java.util.Objects; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.UriInfo; -import redis.clients.jedis.Jedis; - -/** - * A JAX-RS resource class rooted at {@code /jedis}. - * - * @see #get(String) - * - * @see #set(UriInfo, String, String) - * - * @see #del(String) - */ -@Path("/jedis") -@ApplicationScoped -public class RedisClientResource { - - private final Provider clientProvider; - - /** - * Creates a new {@link RedisClientResource}. - * - * @param clientProvider a {@link Provider} of a {@link Jedis} - * instance; must not be {@code null} - * - * @exception NullPointerException if {@code clientProvider} is - * {@code null} - */ - @Inject - public RedisClientResource(final Provider clientProvider) { - super(); - this.clientProvider = Objects.requireNonNull(clientProvider); - } - - /** - * Returns a non-{@code null} {@link Response} which, if successful, - * will contain any value indexed under the supplied Redis key. - * - *

This method never returns {@code null}.

- * - * @param key the key whose value should be deleted; must not be - * {@code null} - * - * @return a non-{@code null} {@link Response} - * - * @see #set(UriInfo, String, String) - * - * @see #del(String) - */ - @GET - @Path("/{key}") - @Produces(MediaType.TEXT_PLAIN) - public Response get(@PathParam("key") final String key) { - final Response returnValue; - if (key == null || key.isEmpty()) { - returnValue = Response.status(400) - .build(); - } else { - final String response = this.clientProvider.get().get(key); - if (response == null) { - returnValue = Response.status(404) - .build(); - } else { - returnValue = Response.ok() - .entity(response) - .build(); - } - } - return returnValue; - } - - /** - * Sets a value under a key in a Redis system. - * - * @param uriInfo a {@link UriInfo} describing the current request; - * must not be {@code null} - * - * @param key the key in question; must not be {@code null} - * - * @param value the value to set; may be {@code null} - * - * @return a non-{@code null} {@link Response} indicating the status - * of the operation - * - * @exception NullPointerException if {@code uriInfo} is {@code - * null} - * - * @see #del(String) - */ - @PUT - @Path("/{key}") - @Consumes(MediaType.TEXT_PLAIN) - public Response set(@Context final UriInfo uriInfo, - @PathParam("key") final String key, - final String value) { - Objects.requireNonNull(uriInfo); - final Response returnValue; - if (key == null || key.isEmpty() || value == null) { - returnValue = Response.status(400) - .build(); - } else { - final Object priorValue = this.clientProvider.get().getSet(key, value); - if (priorValue == null) { - returnValue = Response.created(uriInfo.getRequestUri()) - .build(); - } else { - returnValue = Response.ok() - .build(); - } - } - return returnValue; - } - - /** - * Deletes a value from Redis. - * - * @param key the key identifying the value to delete; must not be - * {@code null} - * - * @return a non-{@code null} {@link Response} describing the result - * of the operation - * - * @see #get(String) - * - * @see #set(UriInfo, String, String) - */ - @DELETE - @Path("/{key}") - @Produces(MediaType.TEXT_PLAIN) - public Response del(@PathParam("key") final String key) { - final Response returnValue; - if (key == null || key.isEmpty()) { - returnValue = Response.status(400) - .build(); - } else { - final Long numberOfKeysDeleted = this.clientProvider.get().del(key); - if (numberOfKeysDeleted == null || numberOfKeysDeleted.longValue() <= 0L) { - returnValue = Response.status(404) - .build(); - } else { - returnValue = Response.noContent() - .build(); - } - } - return returnValue; - } - -} diff --git a/examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/package-info.java b/examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/package-info.java deleted file mode 100644 index 526557b043a..00000000000 --- a/examples/integrations/cdi/jedis/src/main/java/io/helidon/integrations/examples/jedis/jaxrs/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Provides JAX-RS-related classes and interfaces for this example - * project. - */ -package io.helidon.integrations.examples.jedis.jaxrs; diff --git a/examples/integrations/cdi/jedis/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/jedis/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/integrations/cdi/jedis/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/jedis/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/jedis/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 8fcc352c34d..00000000000 --- a/examples/integrations/cdi/jedis/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Jedis properties -redis.clients.jedis.JedisPool.default.port=6379 - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/jpa/README.md b/examples/integrations/cdi/jpa/README.md deleted file mode 100644 index c505468b4d8..00000000000 --- a/examples/integrations/cdi/jpa/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# JPA Integration Example - -With Java: -```bash -mvn package -java -jar target/helidon-integrations-examples-jpa.jar -``` - -Try the endpoint: -```bash -curl -X POST -H "Content-Type: text/plain" http://localhost:8080/foo -d 'bar' -curl http://localhost:8080/foo -``` diff --git a/examples/integrations/cdi/jpa/pom.xml b/examples/integrations/cdi/jpa/pom.xml deleted file mode 100644 index ac2a593319e..00000000000 --- a/examples/integrations/cdi/jpa/pom.xml +++ /dev/null @@ -1,187 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-integrations-examples-jpa - Helidon CDI Extensions Examples JPA - - - - - - jakarta.annotation - jakarta.annotation-api - compile - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.inject - jakarta.inject-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - jakarta.persistence - jakarta.persistence-api - compile - - - jakarta.transaction - jakarta.transaction-api - compile - - - - - com.h2database - h2 - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-eclipselink - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-jta-weld - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-jpa - runtime - - - org.jboss - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - org.eclipse.microprofile.config - microprofile-config-api - runtime - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - org.hibernate.orm - hibernate-jpamodelgen - ${version.lib.hibernate} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - org.codehaus.mojo - exec-maven-plugin - - - weave - process-classes - - java - - - org.eclipse.persistence.tools.weaving.jpa.StaticWeave - - -loglevel - INFO - ${project.build.outputDirectory} - ${project.build.outputDirectory} - - - - - - - - diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/Greeting.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/Greeting.java deleted file mode 100644 index 3ff5bd5e580..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/Greeting.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.integrations.cdi.jpa; - -import java.util.Objects; - -import jakarta.persistence.Access; -import jakarta.persistence.AccessType; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; - -/** - * A contrived representation for example purposes only of a two-part - * greeting as might be stored in a database. - */ -@Access(AccessType.FIELD) -@Entity(name = "Greeting") -@Table(name = "GREETING") -public class Greeting { - - @Id - @Column(name = "FIRSTPART", insertable = true, nullable = false, updatable = false) - private String firstPart; - - @Basic(optional = false) - @Column(name = "SECONDPART", insertable = true, nullable = false, updatable = true) - private String secondPart; - - /** - * Creates a new {@link Greeting}; required by the JPA - * specification and for no other purpose. - * - * @deprecated Please use the {@link #Greeting(String, - * String)} constructor instead. - * - * @see #Greeting(String, String) - */ - @Deprecated - protected Greeting() { - super(); - } - - /** - * Creates a new {@link Greeting}. - * - * @param firstPart the first part of the greeting; must not be - * {@code null} - * - * @param secondPart the second part of the greeting; must not be - * {@code null} - * - * @exception NullPointerException if {@code firstPart} or {@code - * secondPart} is {@code null} - */ - public Greeting(final String firstPart, final String secondPart) { - super(); - this.firstPart = Objects.requireNonNull(firstPart); - this.secondPart = Objects.requireNonNull(secondPart); - } - - /** - * Sets the second part of this greeting. - * - * @param secondPart the second part of this greeting; must not be - * {@code null} - * - * @exception NullPointerException if {@code secondPart} is {@code - * null} - */ - public void setSecondPart(final String secondPart) { - this.secondPart = Objects.requireNonNull(secondPart); - } - - /** - * Returns a {@link String} representation of the second part of - * this {@link Greeting}. - * - *

This method never returns {@code null}.

- * - * @return a non-{@code null} {@link String} representation of the - * second part of this {@link Greeting} - */ - @Override - public String toString() { - return this.secondPart; - } - -} diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldApplication.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldApplication.java deleted file mode 100644 index 790f687ec5d..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldApplication.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.integrations.cdi.jpa; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.core.Application; - -/** - * An example {@link Application} demonstrating the modular - * integration of JPA and JTA with Helidon MicroProfile. - */ -@ApplicationScoped -public class HelloWorldApplication extends Application { - - private final Set> classes; - - /** - * Creates a new {@link HelloWorldApplication}. - */ - public HelloWorldApplication() { - super(); - final Set> classes = new HashSet<>(); - classes.add(HelloWorldResource.class); - classes.add(JPAExceptionMapper.class); - this.classes = Collections.unmodifiableSet(classes); - } - - /** - * Returns a non-{@code null} {@link Set} of {@link Class}es that - * comprise this JAX-RS application. - * - * @return a non-{@code null}, {@linkplain - * Collections#unmodifiableSet(Set) unmodifiable Set} - * - * @see HelloWorldResource - */ - @Override - public Set> getClasses() { - return this.classes; - } - -} diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldResource.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldResource.java deleted file mode 100644 index ff9f83794d9..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldResource.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.integrations.cdi.jpa; - -import java.net.URI; -import java.util.Objects; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.persistence.PersistenceException; -import jakarta.transaction.Status; -import jakarta.transaction.SystemException; -import jakarta.transaction.Transaction; -import jakarta.transaction.Transactional; -import jakarta.transaction.Transactional.TxType; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * A JAX-RS root resource class that manipulates greetings in a - * database. - * - * @see #get(String) - * - * @see #post(String, String) - */ -@Path("") -@RequestScoped -public class HelloWorldResource { - - /** - * The {@link EntityManager} used by this class. - * - *

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

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

- * Examples: - *

{@code
- * Get default greeting message:
- * curl -X GET http://localhost:8080/greet
- *
- * Get greeting message for Joe:
- * curl -X GET http://localhost:8080/greet/Joe
- *
- * Change greeting
- * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting
- *
- * }
- * The greeting message is returned as a JSON object. - * - *

- */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - private final Timer getTimer; - private final Counter personalizedGetCounter; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - GreetService(Config config, Timer getTimer, Counter personalizedGetCounter) { - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - this.getTimer = getTimer; - this.personalizedGetCounter = personalizedGetCounter; - } - - /** - * A service registers itself by updating the routine rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get((req, resp) -> getTimer.record((Runnable) req::next)) // Update the timer with every GET. - .get("/", this::getDefaultMessageHandler) - .get("/{name}", - (req, resp) -> { - personalizedGetCounter.increment(); - req.next(); - }, // Count personalized GETs... - this::getMessageHandler) // ...and process them. - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - GreetingMessage msg = new GreetingMessage(String.format("%s %s!", greeting, name)); - response.send(msg.forRest()); - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey(GreetingMessage.JSON_LABEL)) { - JsonObject jsonErrorObject = JSON_BF.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting = GreetingMessage.fromRest(jo).getMessage(); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class).thenAccept(jo -> updateGreetingFromJson(jo, response)); - } -} diff --git a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/GreetingMessage.java b/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/GreetingMessage.java deleted file mode 100644 index 055a06774be..00000000000 --- a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/GreetingMessage.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.micrometer.se; - -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * POJO for the greeting message exchanged between the server and the client. - */ -public class GreetingMessage { - - /** - * Label for tagging a {@code GreetingMessage} instance in JSON. - */ - public static final String JSON_LABEL = "greeting"; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private String message; - - /** - * Create a new greeting with the specified message content. - * - * @param message the message to store in the greeting - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Returns the message value. - * - * @return the message - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message value to be set - */ - public void setMessage(String message) { - this.message = message; - } - - /** - * Converts a JSON object (typically read from the request payload) - * into a {@code GreetingMessage}. - * - * @param jsonObject the {@link JsonObject} to convert. - * @return {@code GreetingMessage} set according to the provided object - */ - public static GreetingMessage fromRest(JsonObject jsonObject) { - return new GreetingMessage(jsonObject.getString(JSON_LABEL)); - } - - /** - * Prepares a {@link JsonObject} corresponding to this instance. - * - * @return {@code JsonObject} representing this {@code GreetingMessage} instance - */ - public JsonObject forRest() { - JsonObjectBuilder builder = JSON_BF.createObjectBuilder(); - return builder.add(JSON_LABEL, message) - .build(); - } -} diff --git a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/Main.java b/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/Main.java deleted file mode 100644 index 1f2912592f0..00000000000 --- a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/Main.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.micrometer.se; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.integrations.micrometer.MicrometerSupport; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import io.micrometer.core.instrument.Counter; -import io.micrometer.core.instrument.Timer; - -/** - * Simple Hello World rest application. - */ -public final class Main { - - static final String PERSONALIZED_GETS_COUNTER_NAME = "personalizedGets"; - static final String ALL_GETS_TIMER_NAME = "allGets"; - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // Get webserver config from the "server" section of application.yaml - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .port(-1) - .addMediaSupport(JsonpSupport.create()) - .build(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - // Server threads are not daemon. No need to block. Just react. - return server.start() - .peek(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .onError(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, Micrometer metrics, and the greeting service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - MicrometerSupport micrometerSupport = MicrometerSupport.create(); - Counter personalizedGetCounter = micrometerSupport.registry() - .counter(PERSONALIZED_GETS_COUNTER_NAME); - Timer getTimer = Timer.builder(ALL_GETS_TIMER_NAME) - .publishPercentileHistogram() - .register(micrometerSupport.registry()); - - GreetService greetService = new GreetService(config, getTimer, personalizedGetCounter); - - return Routing.builder() - .register(micrometerSupport) // Micrometer support at "/micrometer" - .register("/greet", greetService) - .build(); - } -} diff --git a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/package-info.java b/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/package-info.java deleted file mode 100644 index eb46268faa5..00000000000 --- a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/micrometer/se/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example application showing Micrometer support in Helidon SE - *

- * Start with {@link io.helidon.examples.micrometer.se.Main} class. - * - * @see io.helidon.examples.micrometer.se.Main - */ -package io.helidon.examples.micrometer.se; diff --git a/examples/integrations/micrometer/se/src/main/resources/application.yaml b/examples/integrations/micrometer/se/src/main/resources/application.yaml deleted file mode 100644 index 12336d5f138..00000000000 --- a/examples/integrations/micrometer/se/src/main/resources/application.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - - diff --git a/examples/integrations/micrometer/se/src/test/java/io/helidon/examples/micrometer/se/MainTest.java b/examples/integrations/micrometer/se/src/test/java/io/helidon/examples/micrometer/se/MainTest.java deleted file mode 100644 index f36ec96bcb8..00000000000 --- a/examples/integrations/micrometer/se/src/test/java/io/helidon/examples/micrometer/se/MainTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.micrometer.se; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.CoreMatchers.containsString; - -// we need to first call the methods, before validating metrics -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class MainTest { - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - private static WebServer webServer; - private static WebClient webClient; - - private static double expectedPersonalizedGets; - private static double expectedAllGets; - - static { - TEST_JSON_OBJECT = JSON_BF.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - @BeforeAll - public static void startTheServer() { - webServer = Main.startServer() - .await(10, TimeUnit.SECONDS); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - public static void stopServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - private static JsonObject get() { - return get("/greet"); - } - - private static JsonObject get(String path) { - JsonObject jsonObject = webClient.get() - .path(path) - .request(JsonObject.class) - .await(); - expectedAllGets++; - return jsonObject; - } - - private static JsonObject personalizedGet(String name) { - JsonObject result = get("/greet/" + name); - expectedPersonalizedGets++; - return result; - } - - @Test - @Order(1) - void testDefaultGreeting() { - JsonObject jsonObject = get(); - assertThat(jsonObject.getString("greeting"), is("Hello World!")); - } - - @Test - @Order(2) - void testNamedGreeting() { - JsonObject jsonObject = personalizedGet("Joe"); - Assertions.assertEquals("Hello Joe!", jsonObject.getString("greeting")); - } - - @Test - @Order(3) - void testUpdateGreeting() { - - WebClientResponse response = webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .await(); - - assertThat(response.status(), is(Http.Status.NO_CONTENT_204)); - - JsonObject jsonObject = personalizedGet("Joe"); - assertThat(jsonObject.getString("greeting"), is("Hola Joe!")); - } - - @Test - @Order(4) - void testMicrometer() { - WebClientResponse response = webClient.get() - .path("/micrometer") - .request() - .await(); - - assertThat(response.status().code(), is(200)); - - String output = response.content() - .as(String.class) - .await(); - String expected = Main.ALL_GETS_TIMER_NAME + "_seconds_count " + expectedAllGets; - assertThat("Unable to find expected all-gets timer count " + expected + "; output is " + output, - output, containsString(expected)); // all gets; the put - // is not counted - assertThat("Unable to find expected all-gets timer sum", output, - containsString(Main.ALL_GETS_TIMER_NAME + "_seconds_sum")); - expected = Main.PERSONALIZED_GETS_COUNTER_NAME + "_total " + expectedPersonalizedGets; - assertThat("Unable to find expected counter result " + expected + "; output is " + output, - output, containsString(expected)); - response.close(); - } -} diff --git a/examples/integrations/micronaut/data/README.md b/examples/integrations/micronaut/data/README.md deleted file mode 100644 index afd82933c78..00000000000 --- a/examples/integrations/micronaut/data/README.md +++ /dev/null @@ -1,146 +0,0 @@ -# Helidon Micronaut Data Example - -This example shows integration with Micronaut Data into Helidon MP. - -## Sources - -This example combines Micronaut Data and CDI. - -### CDI classes - -The following classes are CDI and JAX-RS classes that use injected Micronaut beans: - -- `PetResource` - JAX-RS resource exposing Pet REST API -- `OwnerResource` - JAX-RS resource exposing Owner REST API -- `BeanValidationExceptionMapper` - JAX-RS exception mapper to return correct status code - in case of validation failure - -### Micronaut classes - -The following classes are pure Micronaut beans (and cannot have CDI injected into them) - -- `DbPetRepository` - Micronaut Data repository extending an abstract class -- `DbOwnerRepository` - Micronaut Data repository implementing an interface -- `DbPopulateData` - Micronaut startup event listener to initialize the database -- package `model` - data model of the database - -## Build and run - -Start the application: - -```bash -mvn package -java -jar target/helidon-examples-integrations-micronaut-data.jar -``` - -Access endpoints - -```bash -# Get all pets -curl -i http://localhost:8080/pets -# Get all owners -curl -i http://localhost:8080/owners -# Get a single pet -curl -i http://localhost:8080/pets/Dino -# Get a single owner -curl -i http://localhost:8080/owners/Barney -# To fail input validation -curl -i http://localhost:8080/pets/s -``` - -# To use Oracle XE instead of H2 - -- Update ./pom.xml to replace dependency on micronaut-jdbc-hikari with following -``` - - io.micronaut.sql - micronaut-jdbc-ucp - runtime - -``` - -- Update ./pom.xml to replace dependency on com.h2database with following -``` - - io.helidon.integrations.db - ojdbc - runtime - - - com.oracle.database.jdbc - ucp - runtime - -``` - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java and - ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java to change from - Dialect.H2 to Dialect.ORACLE - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java to change Typehint to - @TypeHint(typeNames = {"oracle.jdbc.OracleDriver"}) - -- Install Oracle XE - Instructions for running XE in a docker container can be found here: https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance - -- Update ./src/main/resources/META-INF/microprofile-config.properties to comment out h2 related datasource.* properties and uncomment+update following ones related to XE. -``` -#datasources.default.url=jdbc:oracle:thin:@localhost:/ -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username=system -#datasources.default.password= -#datasources.default.schema-generate=CREATE_DROP -#datasources.default.dialect=oracle -``` - -# To use Oracle ATP cloud service instead of H2 - -- Update ./pom.xml to replace dependency on micronaut-jdbc-hikari with following -``` - - io.micronaut.sql - micronaut-jdbc-ucp - runtime - -``` - -- Update ./pom.xml to replace dependency on com.h2database with following -``` - - io.helidon.integrations.db - ojdbc - runtime - - - com.oracle.database.jdbc - ucp - runtime - -``` - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java and - ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java to change from - Dialect.H2 to Dialect.ORACLE - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java to change Typehint to - @TypeHint(typeNames = {"oracle.jdbc.OracleDriver"}) - -- Setup ATP - Instructions for ATP setup can be found here: https://blogs.oracle.com/developers/the-complete-guide-to-getting-up-and-running-with-autonomous-database-in-the-cloud - -- Create Schema used by test -``` -CREATE TABLE "PET" ("ID" VARCHAR(36),"OWNER_ID" NUMBER(19) NOT NULL,"NAME" VARCHAR(255) NOT NULL,"TYPE" VARCHAR(255) NOT NULL); -CREATE SEQUENCE "OWNER_SEQ" MINVALUE 1 START WITH 1 NOCACHE NOCYCLE; -CREATE TABLE "OWNER" ("ID" NUMBER(19) PRIMARY KEY NOT NULL,"AGE" NUMBER(10) NOT NULL,"NAME" VARCHAR(255) NOT NULL); -``` - -- Update ./src/main/resources/META-INF/microprofile-config.properties to comment out h2 related datasource.* properties and add uncomment+update following ones related to ATP. -``` -#datasources.default.url=jdbc:oracle:thin:@?TNS_ADMIN= -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username= -#datasources.default.password= -#datasources.default.schema-generate=NONE -#datasources.default.dialect=oracle -``` \ No newline at end of file diff --git a/examples/integrations/micronaut/data/pom.xml b/examples/integrations/micronaut/data/pom.xml deleted file mode 100644 index 07889828ab0..00000000000 --- a/examples/integrations/micronaut/data/pom.xml +++ /dev/null @@ -1,157 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - helidon-examples-integrations-micronaut-data - Helidon Example Integration Micronaut Data - - - - jakarta.persistence - jakarta.persistence-api - provided - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.micronaut.data - micronaut-data-jdbc - - - io.micronaut - micronaut-runtime - - - io.helidon.integrations.micronaut - helidon-integrations-micronaut-cdi - runtime - - - io.helidon.integrations.micronaut - helidon-integrations-micronaut-data - runtime - - - io.micronaut.data - micronaut-data-tx - runtime - - - io.micronaut.sql - micronaut-jdbc-hikari - runtime - - - com.h2database - - - h2 - runtime - - - org.jboss - jandex - runtime - true - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - - - io.micronaut - micronaut-inject-java - ${version.lib.micronaut} - - - io.micronaut - micronaut-validation - ${version.lib.micronaut} - - - io.micronaut.data - micronaut-data-processor - ${version.lib.micronaut.data} - - - io.helidon.integrations.micronaut - helidon-integrations-micronaut-cdi-processor - ${helidon.version} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/BeanValidationExceptionMapper.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/BeanValidationExceptionMapper.java deleted file mode 100644 index ca2f919979a..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/BeanValidationExceptionMapper.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data; - -import javax.validation.ConstraintViolationException; - -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; - -/** - * A JAX-RS provider that maps {@link jakarta.validation.ConstraintViolationException} from bean validation - * to a proper JAX-RS response with {@link jakarta.ws.rs.core.Response.Status#BAD_REQUEST} status. - * If this provider is not present, validation exception from Micronaut would end with an internal server - * error. - */ -@Provider -public class BeanValidationExceptionMapper implements ExceptionMapper { - @Override - public Response toResponse(ConstraintViolationException exception) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(exception.getMessage()) - .build(); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java deleted file mode 100644 index f2fc239475c..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data; - -import java.util.List; -import java.util.Optional; - -import io.helidon.examples.integrations.micronaut.data.model.Owner; - -import io.micronaut.data.jdbc.annotation.JdbcRepository; -import io.micronaut.data.model.query.builder.sql.Dialect; -import io.micronaut.data.repository.CrudRepository; - -/** - * Micronaut Data repository for pet owners. - */ -@JdbcRepository(dialect = Dialect.H2) -public interface DbOwnerRepository extends CrudRepository { - /** - * Get all owners from the database. - * - * @return all owners - */ - @Override - List findAll(); - - /** - * Find an owner by name. - * - * @param name name of owner - * @return owner if found - */ - Optional findByName(String name); -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPetRepository.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPetRepository.java deleted file mode 100644 index 0763abc32ca..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPetRepository.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import io.helidon.examples.integrations.micronaut.data.model.NameDTO; -import io.helidon.examples.integrations.micronaut.data.model.Pet; - -import io.micronaut.data.annotation.Join; -import io.micronaut.data.jdbc.annotation.JdbcRepository; -import io.micronaut.data.model.Pageable; -import io.micronaut.data.model.query.builder.sql.Dialect; -import io.micronaut.data.repository.PageableRepository; - -/** - * Micronaut data repository for pets. - */ -@JdbcRepository(dialect = Dialect.H2) -public abstract class DbPetRepository implements PageableRepository { - - /** - * Get all pets. - * - * @param pageable pageable instance - * @return list of pets - */ - public abstract List list(Pageable pageable); - - /** - * Find a pet by its name. - * - * @param name pet name - * @return pet if it was found - */ - @Join("owner") - public abstract Optional findByName(String name); -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java deleted file mode 100644 index 9ff63da26aa..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - This class is almost exactly copied from Micronaut examples. - */ -package io.helidon.examples.integrations.micronaut.data; - -import java.util.Arrays; - -import io.helidon.examples.integrations.micronaut.data.model.Owner; -import io.helidon.examples.integrations.micronaut.data.model.Pet; - -import io.micronaut.context.event.StartupEvent; -import io.micronaut.core.annotation.TypeHint; -import io.micronaut.runtime.event.annotation.EventListener; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -/** - * A Micronaut bean that listens on startup event and populates database with data. - */ -@Singleton -@TypeHint(typeNames = {"org.h2.Driver", "org.h2.mvstore.db.MVTableEngine"}) -public class DbPopulateData { - private final DbOwnerRepository ownerRepository; - private final DbPetRepository petRepository; - - @Inject - DbPopulateData(DbOwnerRepository ownerRepository, DbPetRepository petRepository) { - this.ownerRepository = ownerRepository; - this.petRepository = petRepository; - } - - @EventListener - void init(StartupEvent event) { - Owner fred = new Owner("Fred"); - fred.setAge(45); - Owner barney = new Owner("Barney"); - barney.setAge(40); - ownerRepository.saveAll(Arrays.asList(fred, barney)); - - Pet dino = new Pet("Dino", fred); - Pet bp = new Pet("Baby Puss", fred); - bp.setType(Pet.PetType.CAT); - Pet hoppy = new Pet("Hoppy", barney); - - petRepository.saveAll(Arrays.asList(dino, bp, hoppy)); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/OwnerResource.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/OwnerResource.java deleted file mode 100644 index 6dbb83b60dc..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/OwnerResource.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data; - -import io.helidon.examples.integrations.micronaut.data.model.Owner; - -import jakarta.inject.Inject; -import jakarta.validation.constraints.Pattern; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import org.eclipse.microprofile.metrics.annotation.SimplyTimed; - -/** - * JAX-RS resource, and the MicroProfile entry point to manage pet owners. - * This resource used Micronaut data beans (repositories) to query database, and - * bean validation as implemented by Micronaut. - */ -@Path("/owners") -public class OwnerResource { - private final DbOwnerRepository ownerRepository; - - /** - * Create a new instance with repository. - * - * @param ownerRepo owner repository from Micronaut data - */ - @Inject - public OwnerResource(DbOwnerRepository ownerRepo) { - this.ownerRepository = ownerRepo; - } - - /** - * Gets all owners from the database. - * @return all owners, using JSON-B to map them to JSON - */ - @GET - public Iterable getAll() { - return ownerRepository.findAll(); - } - - /** - * Get a named owner from the database. - * - * @param name name of the owner to find, must be at least two characters long, may contain whitespace - * @return a single owner - * @throws jakarta.ws.rs.NotFoundException in case the owner is not in the database (to return 404 status) - */ - @Path("/{name}") - @GET - @SimplyTimed - public Owner owner(@PathParam("name") @Pattern(regexp = "\\w+[\\w+\\s?]*\\w") String name) { - return ownerRepository.findByName(name) - .orElseThrow(() -> new NotFoundException("Owner by name " + name + " does not exist")); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/PetResource.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/PetResource.java deleted file mode 100644 index 4c18e721b84..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/PetResource.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data; - -import javax.validation.constraints.Pattern; - -import io.helidon.examples.integrations.micronaut.data.model.Pet; - -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import org.eclipse.microprofile.metrics.annotation.SimplyTimed; - -/** - * JAX-RS resource, and the MicroProfile entry point to manage pets. - * This resource used Micronaut data beans (repositories) to query database, and - * bean validation as implemented by Micronaut. - */ -@Path("/pets") -public class PetResource { - private final DbPetRepository petRepository; - - /** - * Create a new instance with pet repository. - * - * @param petRepo Pet repository from Micronaut data - */ - @Inject - public PetResource(DbPetRepository petRepo) { - this.petRepository = petRepo; - } - - /** - * Gets all pets from the database. - * @return all pets, using JSON-B to map them to JSON - */ - @GET - public Iterable getAll() { - return petRepository.findAll(); - } - - /** - * Get a named pet from the database. - * - * @param name name of the pet to find, must be at least two characters long, may contain whitespace - * @return a single pet - * @throws jakarta.ws.rs.NotFoundException in case the pet is not in the database (to return 404 status) - */ - @Path("/{name}") - @GET - @SimplyTimed - public Pet pet(@PathParam("name") @Pattern(regexp = "\\w+[\\w+\\s?]*\\w") String name) { - return petRepository.findByName(name) - .orElseThrow(() -> new NotFoundException("Pet by name " + name + " does not exist")); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/NameDTO.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/NameDTO.java deleted file mode 100644 index 1b299545c2d..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/NameDTO.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data.model; - -import io.micronaut.core.annotation.Introspected; - -/** - * Used in list of names of pets. - */ -@Introspected -public class NameDTO { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Owner.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Owner.java deleted file mode 100644 index 63cdcbe423b..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Owner.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data.model; - -import io.micronaut.core.annotation.Creator; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; - -/** - * Owner database entity. - */ -@Entity -public class Owner { - - @Id - @GeneratedValue - private Long id; - private String name; - private int age; - - /** - * Create a named owner. - * - * @param name name of the owner - */ - @Creator - public Owner(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public String getName() { - return name; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Pet.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Pet.java deleted file mode 100644 index 25e1ec00551..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Pet.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data.model; - -import java.util.UUID; - -import io.micronaut.core.annotation.Creator; -import io.micronaut.core.annotation.Nullable; -import io.micronaut.data.annotation.AutoPopulated; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; - -/** - * Pet database entity. - */ -@Entity -public class Pet { - - @Id - @AutoPopulated - private UUID id; - private String name; - @ManyToOne - private Owner owner; - private PetType type = PetType.DOG; - - /** - * Creates a new pet. - * @param name name of the pet - * @param owner owner of the pet (optional) - */ - // NOTE - please use Nullable from this package, jakarta.annotation.Nullable will fail with JPMS, - // as it is declared in the same package as is used by annother module (jakarta.annotation-api) - @Creator - public Pet(String name, @Nullable Owner owner) { - this.name = name; - this.owner = owner; - } - - public Owner getOwner() { - return owner; - } - - public String getName() { - return name; - } - - public UUID getId() { - return id; - } - - public PetType getType() { - return type; - } - - public void setType(PetType type) { - this.type = type; - } - - public void setId(UUID id) { - this.id = id; - } - - /** - * Type of pet. - */ - public enum PetType { - /** - * Dog. - */ - DOG, - /** - * Cat. - */ - CAT - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/package-info.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/package-info.java deleted file mode 100644 index 054b464733d..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Model classes for entities and transfer objects. - */ -package io.helidon.examples.integrations.micronaut.data.model; diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/package-info.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/package-info.java deleted file mode 100644 index 94bf5dc2f9c..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example showing use of Micronaut Data in Helidon MicroProfile server. - */ -package io.helidon.examples.integrations.micronaut.data; diff --git a/examples/integrations/micronaut/data/src/main/resources/META-INF/beans.xml b/examples/integrations/micronaut/data/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/integrations/micronaut/data/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/micronaut/data/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/micronaut/data/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 7e187711976..00000000000 --- a/examples/integrations/micronaut/data/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server.port=8080 - -#When native image is used, we must use remote h2 -#datasources.default.url=jdbc:h2:tcp://localhost:9092/test -datasources.default.url=jdbc:h2:mem:devDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE -datasources.default.driverClassName=org.h2.Driver -datasources.default.username=sa -datasources.default.password=${EMPTY} -datasources.default.schema-generate=CREATE_DROP -datasources.default.dialect=h2 - -#datasources.default.url=jdbc:oracle:thin:@localhost:/ -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username=system -#datasources.default.password= -#datasources.default.schema-generate=CREATE_DROP -#datasources.default.dialect=oracle - -#datasources.default.url=jdbc:oracle:thin:@?TNS_ADMIN= -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username= -#datasources.default.password= -#datasources.default.schema-generate=NONE -#datasources.default.dialect=oracle diff --git a/examples/integrations/micronaut/data/src/main/resources/logging.properties b/examples/integrations/micronaut/data/src/main/resources/logging.properties deleted file mode 100644 index 06e9fa7e63c..00000000000 --- a/examples/integrations/micronaut/data/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO diff --git a/examples/integrations/micronaut/data/src/test/java/io/helidon/examples/integrations/micronaut/data/MicronautExampleTest.java b/examples/integrations/micronaut/data/src/test/java/io/helidon/examples/integrations/micronaut/data/MicronautExampleTest.java deleted file mode 100644 index 44b5d1de35a..00000000000 --- a/examples/integrations/micronaut/data/src/test/java/io/helidon/examples/integrations/micronaut/data/MicronautExampleTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.micronaut.data; - -import io.helidon.examples.integrations.micronaut.data.model.Pet; -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -class MicronautExampleTest { - @Inject - private WebTarget webTarget; - - @Test - void testAllPets() { - JsonArray jsonValues = webTarget.path("/pets") - .request() - .get(JsonArray.class); - - assertThat("We should get all pets", jsonValues.size(), is(3)); - } - - @Test - void testGetPet() { - JsonObject pet = webTarget.path("/pets/Dino") - .request() - .get(JsonObject.class); - - assertThat(pet.getString("name"), is("Dino")); - assertThat(pet.getString("type"), is(Pet.PetType.DOG.toString())); - } - - @Test - void testNotFound() { - try (Response response = webTarget.path("/pets/Fino") - .request() - .get()) { - assertThat("Should be not found: 404", response.getStatus(), is(404)); - } - } - - @Test - void testValidationError() { - try (Response response = webTarget.path("/pets/a") - .request() - .get()) { - assertThat("Should be bad request: 400", response.getStatus(), is(400)); - } - } - -} \ No newline at end of file diff --git a/examples/integrations/micronaut/pom.xml b/examples/integrations/micronaut/pom.xml deleted file mode 100644 index 94470f1f496..00000000000 --- a/examples/integrations/micronaut/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 3.2.7-SNAPSHOT - - io.helidon.examples.integrations.micronaut - helidon-examples-integrations-micronaut-project - pom - Helidon Micronaut Integration Examples - - - data - - diff --git a/examples/integrations/microstream/README.md b/examples/integrations/microstream/README.md deleted file mode 100644 index d48be20727c..00000000000 --- a/examples/integrations/microstream/README.md +++ /dev/null @@ -1 +0,0 @@ -# Microstream Integrations Examples diff --git a/examples/integrations/microstream/greetings-mp/README.md b/examples/integrations/microstream/greetings-mp/README.md deleted file mode 100644 index 850b81bffc9..00000000000 --- a/examples/integrations/microstream/greetings-mp/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Microstream integration example - -This example uses Microstream to persist the greetings supplied - -## Build and run - -``` -mvn package -java -jar target/helidon-examples-integrations-microstream-greetings-mp.jar -``` - -## Endpoints - -Get default greeting message: -curl -X GET http://localhost:7001/greet - -Get greeting message for Joe: -curl -X GET http://localhost:7001/greet/Joe - -Add a greeting: -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:7001/greet/greeting diff --git a/examples/integrations/microstream/greetings-mp/pom.xml b/examples/integrations/microstream/greetings-mp/pom.xml deleted file mode 100644 index 42e26bcce4c..00000000000 --- a/examples/integrations/microstream/greetings-mp/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - - helidon-examples-integrations-microstream-greetings-mp - Helidon Microstream Integration Example Greetings mp - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.microstream - helidon-integrations-microstream-cdi - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - - \ No newline at end of file diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetResource.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetResource.java deleted file mode 100644 index 314f2df567a..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetResource.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.mp; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:7001/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:7001/greet/Joe - * - * add a greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:7001/greet/greeting - * - * The message is returned as a JSON object - */ -@Path("/greet") -@RequestScoped -public class GreetResource { - - private final GreetingProvider greetingProvider; - - /** - * Using constructor injection to get a configuration property. - * By default this gets the value from META-INF/microprofile-config - * - * @param greetingConfig the configured greeting message - */ - @Inject - public GreetResource(GreetingProvider greetingConfig) { - this.greetingProvider = greetingConfig; - } - - /** - * Return a default greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getGreeting(), who); - - return new GreetingMessage(msg); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.addGreeting(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - -} diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingMessage.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingMessage.java deleted file mode 100644 index e57afc8b6d6..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.integrations.microstream.greetings.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingProvider.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingProvider.java deleted file mode 100644 index f4c6446ab5c..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.mp; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import io.helidon.integrations.microstream.cdi.MicrostreamStorage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import one.microstream.storage.embedded.types.EmbeddedStorageManager; - -/** - * Provider for greeting message that are persisted by microstream. - */ -@ApplicationScoped -public class GreetingProvider { - - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - private final EmbeddedStorageManager storage; - private final Random rnd = new Random(); - - private List greetingMessages; - - /** - * Creates new GreetingProvider using a microstream EmbeddedStorageManager. - * - * @param storage the used EmbeddedStorageManager. - */ - @SuppressWarnings("unchecked") - @Inject - public GreetingProvider(@MicrostreamStorage(configNode = "one.microstream.storage.greetings") - EmbeddedStorageManager storage) { - super(); - this.storage = storage; - - // load stored data - greetingMessages = (List) storage.root(); - - // Initialize storage if empty - if (greetingMessages == null) { - greetingMessages = new ArrayList<>(); - storage.setRoot(greetingMessages); - storage.storeRoot(); - addGreeting("Hello"); - } - } - - /** - * Add a new greeting to the available greetings and persist it. - * - * @param newGreeting the new greeting to be added and persisted. - */ - public void addGreeting(String newGreeting) { - try { - lock.writeLock().lock(); - greetingMessages.add(newGreeting); - storage.store(greetingMessages); - } finally { - lock.writeLock().unlock(); - } - } - - /** - * returns a random greeting. - * - * @return a greeting. - */ - public String getGreeting() { - try { - lock.readLock().lock(); - return greetingMessages.get(rnd.nextInt(greetingMessages.size())); - } finally { - lock.readLock().unlock(); - } - } - -} diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/package-info.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/package-info.java deleted file mode 100644 index 01a14d7ff31..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * An example that uses Microstream to persist the greetings. - */ -package io.helidon.examples.integrations.microstream.greetings.mp; diff --git a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/beans.xml b/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 586bf9ea47a..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (c) 2021, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -one.microstream.storage.greetings.storage-directory=./greetingsStorage diff --git a/examples/integrations/microstream/greetings-mp/src/test/java/io/helidon/examples/integrations/microstream/greetings/mp/MicrostreamExampleGreetingsMpTest.java b/examples/integrations/microstream/greetings-mp/src/test/java/io/helidon/examples/integrations/microstream/greetings/mp/MicrostreamExampleGreetingsMpTest.java deleted file mode 100644 index 622dfabcae6..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/test/java/io/helidon/examples/integrations/microstream/greetings/mp/MicrostreamExampleGreetingsMpTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.mp; - -import java.nio.file.Path; - -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.WebTarget; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@HelidonTest -class MicrostreamExampleGreetingsMpTest { - - @Inject - private WebTarget webTarget; - - @TempDir - static Path tempDir; - - @BeforeAll - static void beforeAll() { - System.setProperty("one.microstream.storage.greetings.storage-directory", tempDir.toString()); - } - - @Test - void testGreeting() { - GreetingMessage response = webTarget.path("/greet").request().get(GreetingMessage.class); - - assertEquals("Hello World!", response.getMessage(), "response should be 'Hello World' "); - } - -} diff --git a/examples/integrations/microstream/greetings-se/README.md b/examples/integrations/microstream/greetings-se/README.md deleted file mode 100644 index c05d202abf8..00000000000 --- a/examples/integrations/microstream/greetings-se/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Microstream integration example - -This example uses Microstream to persist a log entry for every greeting - -## Build and run - -``` -mvn package -java -jar target/helidon-examples-integrations-microstream-greetings-se.jar -``` - -## Endpoints - -Get default greeting message: -curl -X GET http://localhost:8080/greet - -Get greeting message for Joe: -curl -X GET http://localhost:8080/greet/Joe - -Change greeting: -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - -Get the logs: -curl -X GET http://localhost:8080/greet/logs \ No newline at end of file diff --git a/examples/integrations/microstream/greetings-se/pom.xml b/examples/integrations/microstream/greetings-se/pom.xml deleted file mode 100644 index 578809124c3..00000000000 --- a/examples/integrations/microstream/greetings-se/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - - helidon-examples-integrations-microstream-greetings-se - Helidon Microstream Integration Example Greetings se - - - io.helidon.examples.integrations.microstream.greetings.se.Main - - - - - io.helidon.bundles - helidon-bundles-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - - - io.helidon.integrations.microstream - helidon-integrations-microstream - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - \ No newline at end of file diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingService.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingService.java deleted file mode 100644 index 32306dbc696..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingService.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.integrations.microstream.core.EmbeddedStorageManagerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * Get the logs: - * curl -X GET http://localhost:8080/greet/logs - * - * The message is returned as a JSON object - */ - -public class GreetingService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private static final Logger LOGGER = Logger.getLogger(GreetingService.class.getName()); - - private final GreetingServiceMicrostreamContext mctx; - - GreetingService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - - mctx = new GreetingServiceMicrostreamContext(EmbeddedStorageManagerBuilder.create(config.get("microstream"))); - // we need to initialize the root element first - // if we do not wait here, we have a race where HTTP method may be invoked before we initialize root - mctx.start().await(); - mctx.initRootElement(); - } - - /** - * A service registers itself by updating the routing rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/logs", this::getLog) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - private void getLog(ServerRequest request, - ServerResponse response) { - - mctx.getLogs().thenAccept((logs) -> { - JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder(); - logs.forEach((entry) -> arrayBuilder.add( - JSON.createObjectBuilder() - .add("name", entry.getName()) - .add("time", entry.getDateTime().toString()) - )); - response.send(arrayBuilder.build()); - }).exceptionally(e -> processErrors(e, request, response)); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - mctx.addLogEntry(name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - ex.printStackTrace(); - - if (ex.getCause() instanceof JsonException) { - - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } - -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingServiceMicrostreamContext.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingServiceMicrostreamContext.java deleted file mode 100644 index 7808af13ab5..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingServiceMicrostreamContext.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.se; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import io.helidon.common.reactive.Single; - -import one.microstream.storage.embedded.types.EmbeddedStorageManager; - -/** - * This class extends the MicrostreamSingleThreadedExecutionContext and provides - * data access methods using the MicrostreamSingleThreadedExecutionContext. - */ -public class GreetingServiceMicrostreamContext extends MicrostreamSingleThreadedExecutionContext { - - /** - * Create a new GreetingServiceMicrostreamContext. - * - * @param storageManager the EmbeddedStorageManager used. - */ - public GreetingServiceMicrostreamContext(EmbeddedStorageManager storageManager) { - super(storageManager); - } - - /** - * Add and store a new log entry. - * - * @param name paramter for log text. - * @return Void - */ - public CompletableFuture addLogEntry(String name) { - return execute(() -> { - @SuppressWarnings("unchecked") - List logs = (List) storageManager().root(); - logs.add(new LogEntry(name, LocalDateTime.now())); - storageManager().store(logs); - return null; - }); - } - - /** - * initialize the storage root with a new, empty List. - * - * @return Void - */ - public CompletableFuture initRootElement() { - return execute(() -> { - if (storageManager().root() == null) { - storageManager().setRoot(new ArrayList()); - storageManager().storeRoot(); - } - return null; - }); - } - - /** - * returns a List of all stored LogEntries. - * - * @return all LogEntries. - */ - public Single> getLogs() { - @SuppressWarnings("unchecked") - CompletableFuture> completableFuture = CompletableFuture.supplyAsync(() -> { - return (List) storageManager().root(); - }, executor()); - return (Single>) Single.create(completableFuture); - } - -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/LogEntry.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/LogEntry.java deleted file mode 100644 index df0b73621f7..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/LogEntry.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.se; - -import java.time.LocalDateTime; - -/** - * - * simple POJO that represents a Log entry that is stored by microstream in this example. - * - */ -public class LogEntry { - private String name; - private LocalDateTime dateTime; - - /** - * The Constructor. - * - * @param name name to be logged. - * - * @param dateTime dateTime date and time to be logged - */ - public LogEntry(String name, LocalDateTime dateTime) { - super(); - this.name = name; - this.dateTime = dateTime; - } - - public String getName() { - return name; - } - - public LocalDateTime getDateTime() { - return dateTime; - } - -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/Main.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/Main.java deleted file mode 100644 index 9671c91e23a..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/Main.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.se; - -import java.util.concurrent.TimeUnit; - -import io.helidon.common.LogConfig; -import io.helidon.config.ClasspathConfigSource; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Microstream demo with a simple rest application. - */ -public class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - startServer(); - } - - static WebServer startServer() { - - LogConfig.configureRuntime(); - Config config = Config.builder() - .addSource(ClasspathConfigSource.create("/application.yaml")) - .build(); - - // Build server with JSONP support - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - server.start() - .thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }) - .await(10, TimeUnit.SECONDS); - - // Server threads are not daemon. No need to block. Just react. - return server; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - GreetingService greetService = new GreetingService(config); - - return Routing.builder() - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register("/greet", greetService) - .build(); - } -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamSingleThreadedExecutionContext.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamSingleThreadedExecutionContext.java deleted file mode 100644 index ef042ead9b7..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamSingleThreadedExecutionContext.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.se; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.function.Supplier; - -import io.helidon.common.reactive.Single; - -import one.microstream.reference.LazyReferenceManager; -import one.microstream.storage.embedded.types.EmbeddedStorageManager; - -/** - * - * The MicrostreamSingleThreadedExecutionContext provides a very simply way to ensure - * thread safe access to a Microstream storage and it's associated data. - * - * This example just uses a single-treaded ExecutorService to avoid the need to manually synchronize - * any multi-threaded access to the storage and the user provided object-graph. - * - */ -public class MicrostreamSingleThreadedExecutionContext { - - private final EmbeddedStorageManager storage; - private final ExecutorService executor; - - /** - * Creates a MicrostreamSingleThreadedExecutionContext. - * - * @param storageManager the used EmbeddedStorageManager. - */ - public MicrostreamSingleThreadedExecutionContext(EmbeddedStorageManager storageManager) { - this.storage = storageManager; - this.executor = Executors.newSingleThreadExecutor(); - } - - /** - * returns the used storageManager. - * - * @return the used EmbeddedStorageManager. - */ - public EmbeddedStorageManager storageManager() { - return storage; - } - - /** - * returns the used ExecutorService. - * - * @return the used ExecutorService. - */ - public ExecutorService executor() { - return executor; - } - - /** - * Start the storage. - * - * @return a Single providing the started EmbeddedStorageManager. - */ - public Single start() { - CompletableFuture completableFuture = CompletableFuture.supplyAsync( - storage::start, executor); - - return Single.create(completableFuture); - } - - /** - * Shutdown the storage. - * - * @return a Single providing stopped EmbeddedStorageManager. - */ - public Single shutdown() { - CompletableFuture completableFuture = CompletableFuture.supplyAsync( - () -> { - storage.shutdown(); - LazyReferenceManager.get().stop(); - executor.shutdown(); - return storage; - }, executor); - - return Single.create(completableFuture); - } - - /** - * Return the persistent object graph's root object. - * - * @param type of the root object - * @return a Single containing the graph's root object casted to - */ - public Single root() { - @SuppressWarnings("unchecked") - CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { - return (T) storage.root(); - }, executor); - return Single.create(completableFuture); - } - - /** - * Sets the passed instance as the new root for the persistent object graph. - * - * @param object the new root object - * @return Single containing the new root object - */ - public Single setRoot(Object object) { - CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { - return storage.setRoot(object); - }, executor); - return Single.create(completableFuture); - } - - /** - * Stores the registered root instance. - * - * @return Single containing the root instance's objectId. - */ - public Single storeRoot() { - CompletableFuture completableFuture = CompletableFuture.supplyAsync(storage::storeRoot, executor); - return Single.create(completableFuture); - } - - /** - * Stores the passed object. - * - * @param object - * @return Single containing the object id representing the passed instance. - */ - public Single store(Object object) { - CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { - return storage.store(object); - }, executor); - return Single.create(completableFuture); - } - - /** - * Creates a new CompletableFuture that executes in this context. - * - * @param the return type - * @param supplier a function returning the value to be used to complete the returned CompletableFuture - * @return the new CompletableFuture - */ - public CompletableFuture execute(Supplier supplier) { - CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { - return supplier.get(); - }, executor); - return completableFuture; - } -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/package-info.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/package-info.java deleted file mode 100644 index c72da892914..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * An example that uses Microstream to persist a log entry for every greeting. - */ -package io.helidon.examples.integrations.microstream.greetings.se; diff --git a/examples/integrations/microstream/greetings-se/src/main/resources/application.yaml b/examples/integrations/microstream/greetings-se/src/main/resources/application.yaml deleted file mode 100644 index 425fd59d3f9..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - -microstream: - channel-count: 4 - housekeeping-interval: 2000ms diff --git a/examples/integrations/microstream/greetings-se/src/test/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExampleGreetingsSeTest.java b/examples/integrations/microstream/greetings-se/src/test/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExampleGreetingsSeTest.java deleted file mode 100644 index 6887a8cbf18..00000000000 --- a/examples/integrations/microstream/greetings-se/src/test/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExampleGreetingsSeTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.microstream.greetings.se; - -import java.nio.file.Path; -import java.util.concurrent.TimeUnit; - -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class MicrostreamExampleGreetingsSeTest { - - private static WebServer webServer; - private static WebClient webClient; - - @TempDir - static Path tempDir; - - @BeforeAll - static void startServer() throws Exception { - System.setProperty("microstream.storage-directory", tempDir.toString()); - - webServer = Main.startServer(); - - webClient = WebClient.builder().baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()).build(); - } - - @AfterAll - static void stopServer() throws Exception { - if (webServer != null) { - webServer.shutdown().await(10, TimeUnit.SECONDS); - } - } - - @Test - void testExample() { - JsonObject jsonObject = webClient - .get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(10, TimeUnit.SECONDS); - - assertThat(jsonObject.getString("message"), is("Hello Joe!")); - - JsonArray jsonArray = webClient - .get() - .path("/greet/logs") - .request(JsonArray.class) - .await(10, TimeUnit.SECONDS); - - assertThat(jsonArray.get(0).asJsonObject().getString("name"), is("Joe")); - assertThat(jsonArray.get(0).asJsonObject().getString("time"), notNullValue()); - } -} diff --git a/examples/integrations/microstream/pom.xml b/examples/integrations/microstream/pom.xml deleted file mode 100644 index 114a18aa4ed..00000000000 --- a/examples/integrations/microstream/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 3.2.7-SNAPSHOT - - - io.helidon.examples.integrations.microstream - helidon-examples-integrations-microstream-project - Helidon Microstream Integration Examples - pom - - - greetings-se - greetings-mp - - \ No newline at end of file diff --git a/examples/integrations/neo4j/neo4j-mp/.dockerignore b/examples/integrations/neo4j/neo4j-mp/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/integrations/neo4j/neo4j-mp/Dockerfile b/examples/integrations/neo4j/neo4j-mp/Dockerfile deleted file mode 100644 index 8eeb50924e4..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-integration-neo4j-mp.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-examples-integration-neo4j-mp.jar"] - -EXPOSE 8080 diff --git a/examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink b/examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink deleted file mode 100644 index 3826aac60c2..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/Dockerfile.jlink +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -# Don't generate CDS archive to work around JVM bug https://bugs.openjdk.org/browse/JDK-8274944 -RUN mvn package -Pjlink-image -DskipTests -Djlink.image.addClassDataSharingArchive=false -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/helidon-examples-integration-neo4j-mp-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/integrations/neo4j/neo4j-mp/Dockerfile.native b/examples/integrations/neo4j/neo4j-mp/Dockerfile.native deleted file mode 100644 index 94df93b9d61..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/Dockerfile.native +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2021, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0 as build - -# Install native-image -RUN gu install native-image - -WORKDIR /usr/share - -# Install maven -RUN set -x && \ - curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ - tar -xvf apache-maven-*-bin.tar.gz && \ - rm apache-maven-*-bin.tar.gz && \ - mv apache-maven-* maven && \ - ln -s /usr/share/maven/bin/mvn /bin/ - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM scratch -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-integration-neo4j-mp . - -ENTRYPOINT ["./helidon-examples-integration-neo4j-mp"] - -EXPOSE 8080 diff --git a/examples/integrations/neo4j/neo4j-mp/README.md b/examples/integrations/neo4j/neo4j-mp/README.md deleted file mode 100644 index d925c4b2d94..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/README.md +++ /dev/null @@ -1,167 +0,0 @@ -# Helidon Quickstart MP Example - -This example implements a simple Neo4j REST service using MicroProfile. - -## Build and run - -Bring up a Neo4j instance via Docker - -```bash -docker run --publish=7474:7474 --publish=7687:7687 -e 'NEO4J_AUTH=neo4j/secret' neo4j:4.0 -``` - -Goto the Neo4j browser and play the first step of the movies graph: [`:play movies`](http://localhost:7474/browser/?cmd=play&arg=movies). - - -Then build with JDK11+ -```bash -mvn package -java -jar target/helidon-examples-integration-neo4j-mp.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/movies - -``` - -## Try health and metrics - -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... -. . . - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge -. . . - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -{"base":... -. . . - -``` - -## Build the Docker Image - -``` -docker build -t helidon-integrations-neo4j-mp . -``` - -## Start the application with Docker - -``` -docker run --rm -p 8080:8080 helidon-integrations-neo4j-mp:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -``` -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deploy application -kubectl get service helidon-integrations-neo4j-mp # Verify deployed service -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `20.1.0` or later. - -``` -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-mp -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -``` -docker build -t helidon-integrations-neo4j-mp-native -f Dockerfile.native . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-integrations-neo4j-mp-native:latest -``` - - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -``` -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -``` -./target/helidon-integrations-neo4j-mp-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -``` -docker build -t helidon-integrations-neo4j-mp-jri -f Dockerfile.jlink . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-integrations-neo4j-mp-jri:latest -``` - -See the start script help: - -``` -docker run --rm helidon-integrations-neo4j-mp-jri:latest --help -``` diff --git a/examples/integrations/neo4j/neo4j-mp/app.yaml b/examples/integrations/neo4j/neo4j-mp/app.yaml deleted file mode 100644 index 3359b178eef..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/app.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-examples-integration-neo4j-mp - labels: - app: helidon-examples-integration-neo4j-mp -spec: - type: NodePort - selector: - app: helidon-examples-integration-neo4j-mp - ports: - - port: 8080 - targetPort: 8080 - name: http ---- -kind: Deployment -apiVersion: extensions/v1beta1 -metadata: - name: helidon-examples-integration-neo4j-mp -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-integration-neo4j-mp - version: v1 - spec: - containers: - - name: helidon-examples-integration-neo4j-mp - image: helidon-examples-integration-neo4j-mp - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 ---- diff --git a/examples/integrations/neo4j/neo4j-mp/pom.xml b/examples/integrations/neo4j/neo4j-mp/pom.xml deleted file mode 100644 index 02e3591803d..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/pom.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.neo4j - helidon-examples-integration-neo4j-mp - Helidon Neo4j MP integration Example - - - 5.12.0 - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j-metrics - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j-health - - - - - org.jboss - jandex - runtime - true - - - - - - org.neo4j.test - neo4j-harness - ${neo4j-harness.version} - test - - - org.slf4j - slf4j-nop - - - org.junit.vintage - junit-vintage-engine - - - org.neo4j.app - neo4j-server - - - - - org.neo4j.app - neo4j-server - ${neo4j-harness.version} - test - - - * - * - - - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - - --add-opens=java.base/java.lang=ALL-UNNAMED - - - - - - diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/Neo4jResource.java b/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/Neo4jResource.java deleted file mode 100644 index c35b4d33d93..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/Neo4jResource.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.mp; - -import java.util.List; - -import io.helidon.examples.integrations.neo4j.mp.domain.Movie; -import io.helidon.examples.integrations.neo4j.mp.domain.MovieRepository; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * REST endpoint for movies. - */ -@Path("/movies") -@RequestScoped -public class Neo4jResource { - /** - * The greeting message provider. - */ - private final MovieRepository movieRepository; - - /** - * Constructor. - * - * @param movieRepository - */ - @Inject - public Neo4jResource(MovieRepository movieRepository) { - this.movieRepository = movieRepository; - } - - /** - * All movies. - * - * @return json String with all movies - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public List getAllMovies() { - return movieRepository.findAll(); - } - -} - diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Actor.java b/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Actor.java deleted file mode 100644 index 4b821668180..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Actor.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.mp.domain; - -import java.util.ArrayList; -import java.util.List; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * The Actor class. - * - * @author Michael Simons - */ -public class Actor { - - private final String name; - - private final List roles; - - /** - * Constructor. - * - * @param name - * @param roles - */ - public Actor(String name, final List roles) { - this.name = name; - this.roles = new ArrayList<>(roles); - } -} diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Movie.java b/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Movie.java deleted file mode 100644 index 7d1abcd1455..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Movie.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.mp.domain; - -import java.util.ArrayList; -import java.util.List; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -/** - * The Movie class. - * - * @author Michael Simons - */ -public class Movie { - - private final String title; - - private final String description; - - private List actors = new ArrayList<>(); - - private List directors = new ArrayList<>(); - - private Integer released; - - /** - * Constructor. - * - * @param title - * @param description - */ - public Movie(String title, String description) { - this.title = title; - this.description = description; - } - - public String getTitle() { - return title; - } - - public List getActors() { - return actors; - } - - public void setActors(List actors) { - this.actors = actors; - } - - public String getDescription() { - return description; - } - - public List getDirectors() { - return directors; - } - - public void setDirectorss(List directors) { - this.directors = directors; - } - - public Integer getReleased() { - return released; - } - - public void setReleased(Integer released) { - this.released = released; - } -} diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/MovieRepository.java b/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/MovieRepository.java deleted file mode 100644 index c9eb52cef70..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/MovieRepository.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.mp.domain; - -import java.util.List; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.neo4j.driver.Driver; -import org.neo4j.driver.Value; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * The Movies repository. - * - * @author Michael Simons - */ -@ApplicationScoped -public class MovieRepository { - - private final Driver driver; - - /** - * Constructor. - * @param driver - */ - @Inject - public MovieRepository(Driver driver) { - this.driver = driver; - } - - /** - * Return al Movies. - * @return list with movies - */ - public List findAll() { - - try (var session = driver.session()) { - - var query = "" - + "match (m:Movie) " - + "match (m) <- [:DIRECTED] - (d:Person) " - + "match (m) <- [r:ACTED_IN] - (a:Person) " - + "return m, collect(d) as directors, collect({name:a.name, roles: r.roles}) as actors"; - - return session.readTransaction(tx -> tx.run(query).list(r -> { - var movieNode = r.get("m").asNode(); - - var directors = r.get("directors").asList(v -> { - var personNode = v.asNode(); - return new Person(personNode.get("born").asInt(), personNode.get("name").asString()); - }); - - var actors = r.get("actors").asList(v -> { - return new Actor(v.get("name").asString(), v.get("roles").asList(Value::asString)); - }); - - var m = new Movie(movieNode.get("title").asString(), movieNode.get("tagline").asString()); - m.setReleased(movieNode.get("released").asInt()); - m.setDirectorss(directors); - m.setActors(actors); - return m; - })); - } - } -} diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Person.java b/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Person.java deleted file mode 100644 index 692a58e7e93..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/Person.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.mp.domain; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * The Person class. - * - * @author Michael Simons - */ -public class Person { - - private final String name; - - private Integer born; - - /** - * Person constructor. - * - * @param born - * @param name - */ - public Person(Integer born, String name) { - this.born = born; - this.name = name; - } - - public String getName() { - return name; - } - - public Integer getBorn() { - return born; - } - - public void setBorn(Integer born) { - this.born = born; - } - - @SuppressWarnings("checkstyle:OperatorWrap") - @Override - public String toString() { - return "Person{" + - "name='" + name + '\'' + - ", born=" + born + - '}'; - } -} diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/package-info.java b/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/package-info.java deleted file mode 100644 index 0883266ea9e..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/domain/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Domain objects for movie DB. - */ -package io.helidon.examples.integrations.neo4j.mp.domain; diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/package-info.java b/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/package-info.java deleted file mode 100644 index d78d418a922..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/java/io/helidon/examples/integrations/neo4j/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Resources. - */ -package io.helidon.examples.integrations.neo4j.mp; diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/beans.xml b/examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 70f63d64091..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true - -# Neo4j settings -neo4j.uri=bolt://localhost:7687 -neo4j.authentication.username=neo4j -neo4j.authentication.password: secret -neo4j.pool.metricsEnabled: true diff --git a/examples/integrations/neo4j/neo4j-mp/src/main/resources/logging.properties b/examples/integrations/neo4j/neo4j-mp/src/main/resources/logging.properties deleted file mode 100644 index b5cf2f64627..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO diff --git a/examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/MainTest.java b/examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/MainTest.java deleted file mode 100644 index 15946eb8d7b..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/MainTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.mp; - -import io.helidon.microprofile.server.Server; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.spi.CDI; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.neo4j.harness.Neo4j; -import org.neo4j.harness.Neo4jBuilders; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Main tests of the application done here. - */ -class MainTest { - private static Server server; - private static Neo4j embeddedDatabaseServer; - - @BeforeAll - public static void startTheServer() throws Exception { - - embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() - .withDisabledServer() - .withFixture(FIXTURE) - .build(); - - System.setProperty("neo4j.uri", embeddedDatabaseServer.boltURI().toString()); - - server = Server.create().start(); - - } - - @AfterAll - static void destroyClass() { - CDI current = CDI.current(); - ((SeContainer) current).close(); - embeddedDatabaseServer.close(); - } - - - @Test - void testMovies() { - - Client client = ClientBuilder.newClient(); - - JsonArray jsonArray = client - .target(getConnectionString("/movies")) - .request() - .get(JsonArray.class); - JsonObject first = jsonArray.getJsonObject(0); - assertThat(first.getString("title"), is("The Matrix")); - - } - - private String getConnectionString(String path) { - return "http://localhost:" + server.port() + path; - } - - static final String FIXTURE = """ - CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'}) - CREATE (Keanu:Person {name:'Keanu Reeves', born:1964}) - CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967}) - CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961}) - CREATE (Hugo:Person {name:'Hugo Weaving', born:1960}) - CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967}) - CREATE (LanaW:Person {name:'Lana Wachowski', born:1965}) - CREATE (JoelS:Person {name:'Joel Silver', born:1952}) - CREATE (KevinB:Person {name:'Kevin Bacon', born:1958}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix), - (LillyW)-[:DIRECTED]->(TheMatrix), - (LanaW)-[:DIRECTED]->(TheMatrix), - (JoelS)-[:PRODUCED]->(TheMatrix) - - CREATE (Emil:Person {name:"Emil Eifrem", born:1978}) - CREATE (Emil)-[:ACTED_IN {roles:["Emil"]}]->(TheMatrix) - - CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded), - (LillyW)-[:DIRECTED]->(TheMatrixReloaded), - (LanaW)-[:DIRECTED]->(TheMatrixReloaded), - (JoelS)-[:PRODUCED]->(TheMatrixReloaded) - - CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, tagline:'Everything that has a beginning has an end'}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions), - (KevinB)-[:ACTED_IN {roles:['Unknown']}]->(TheMatrixRevolutions), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions), - (LillyW)-[:DIRECTED]->(TheMatrixRevolutions), - (LanaW)-[:DIRECTED]->(TheMatrixRevolutions), - (JoelS)-[:PRODUCED]->(TheMatrixRevolutions) - """; -} diff --git a/examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/package-info.java b/examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/package-info.java deleted file mode 100644 index acbfc3cde79..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/test/java/io/helidon/examples/integrations/neo4j/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Tests for MP Neo4j app. - */ -package io.helidon.examples.integrations.neo4j.mp; \ No newline at end of file diff --git a/examples/integrations/neo4j/neo4j-mp/src/test/resources/META-INF/microprofile-config.properties b/examples/integrations/neo4j/neo4j-mp/src/test/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 0f7f7a9d224..00000000000 --- a/examples/integrations/neo4j/neo4j-mp/src/test/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -# Override configuration to use a random port for the unit tests -config_ordinal=1000 -# Microprofile server properties -server.port=-1 -server.host=0.0.0.0 diff --git a/examples/integrations/neo4j/neo4j-se/.dockerignore b/examples/integrations/neo4j/neo4j-se/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/integrations/neo4j/neo4j-se/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/integrations/neo4j/neo4j-se/Dockerfile b/examples/integrations/neo4j/neo4j-se/Dockerfile deleted file mode 100644 index bfe5c682281..00000000000 --- a/examples/integrations/neo4j/neo4j-se/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-integration-neo4j-se.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-examples-integration-neo4j-se.jar"] - -EXPOSE 8080 diff --git a/examples/integrations/neo4j/neo4j-se/Dockerfile.jlink b/examples/integrations/neo4j/neo4j-se/Dockerfile.jlink deleted file mode 100644 index c1d7d45899e..00000000000 --- a/examples/integrations/neo4j/neo4j-se/Dockerfile.jlink +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -# Don't generate CDS archive to work around JVM bug https://bugs.openjdk.org/browse/JDK-8274944 -RUN mvn package -Pjlink-image -DskipTests -Djlink.image.addClassDataSharingArchive=false -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/helidon-examples-integration-neo4j-se-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/integrations/neo4j/neo4j-se/Dockerfile.native b/examples/integrations/neo4j/neo4j-se/Dockerfile.native deleted file mode 100644 index df5dbf95aec..00000000000 --- a/examples/integrations/neo4j/neo4j-se/Dockerfile.native +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2021, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0 as build - -# Install native-image -RUN gu install native-image - -WORKDIR /usr/share - -# Install maven -RUN set -x && \ - curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ - tar -xvf apache-maven-*-bin.tar.gz && \ - rm apache-maven-*-bin.tar.gz && \ - mv apache-maven-* maven && \ - ln -s /usr/share/maven/bin/mvn /bin/ - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM scratch -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-integration-neo4j-se . - -ENTRYPOINT ["./helidon-examples-integration-neo4j-se"] - -EXPOSE 8080 diff --git a/examples/integrations/neo4j/neo4j-se/README.md b/examples/integrations/neo4j/neo4j-se/README.md deleted file mode 100644 index 45c0ac6cc39..00000000000 --- a/examples/integrations/neo4j/neo4j-se/README.md +++ /dev/null @@ -1,183 +0,0 @@ -# Helidon SE integration with Neo4J example - -## Build and run - -Bring up a Neo4j instance via Docker - -```bash -docker run --publish=7474:7474 --publish=7687:7687 -e 'NEO4J_AUTH=neo4j/secret' neo4j:4.0 -``` - -Goto the Neo4j browser and play the first step of the movies graph: [`:play movies`](http://localhost:7474/browser/?cmd=play&arg=movies). - -Build and run with With JDK11+ -```bash -mvn package -java -jar target/helidon-examples-integration-neo4j-se.jar -``` - -Then access the rest API like this: - -```` -curl localhost:8080/api/movies -```` - -#Health and metrics - -Heo4jSupport provides health checks and metrics reading from Neo4j. - -To enable them add to routing: -```java -// metrics -Neo4jMetricsSupport.builder() - .driver(neo4j.driver()) - .build() - .initialize(); -// health checks -HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .addReadiness(Neo4jHealthCheck.create(neo4j.driver())) - .build(); - -return Routing.builder() - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register(movieService) - .build(); -``` -and enable them in the driver: -```yaml - pool: - metricsEnabled: true -``` - - -```` -curl localhost:8080/health -```` - -```` -curl localhost:8080/metrics -```` - - - -## Build the Docker Image - -``` -docker build -t helidon-integrations-heo4j-se . -``` - -## Start the application with Docker - -``` -docker run --rm -p 8080:8080 helidon-integrations-heo4j-se:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -``` -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deply application -kubectl get service helidon-integrations-heo4j-se # Get service info -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `20.1.0` or later. - -``` -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -``` -./target/helidon-integrations-heo4j-se -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -``` -docker build -t helidon-integrations-heo4j-se-native -f Dockerfile.native . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-integrations-heo4j-se-native:latest -``` - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -``` -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -``` -./target/helidon-integrations-heo4j-se-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -``` -docker build -t helidon-integrations-heo4j-se-jri -f Dockerfile.jlink . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-integrations-heo4j-se-jri:latest -``` - -See the start script help: - -``` -docker run --rm helidon-integrations-heo4j-se-jri:latest --help -``` diff --git a/examples/integrations/neo4j/neo4j-se/app.yaml b/examples/integrations/neo4j/neo4j-se/app.yaml deleted file mode 100644 index 7028ee6a53a..00000000000 --- a/examples/integrations/neo4j/neo4j-se/app.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-examples-integration-neo4j-se - labels: - app: helidon-examples-integration-neo4j-se -spec: - type: NodePort - selector: - app: helidon-examples-integration-neo4j-se - ports: - - port: 8080 - targetPort: 8080 - name: http ---- -kind: Deployment -apiVersion: extensions/v1beta1 -metadata: - name: helidon-examples-integration-neo4j-se -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-integration-neo4j-se - version: v1 - spec: - containers: - - name: helidon-examples-integration-neo4j-se - image: helidon-examples-integration-neo4j-se - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 ---- diff --git a/examples/integrations/neo4j/neo4j-se/pom.xml b/examples/integrations/neo4j/neo4j-se/pom.xml deleted file mode 100644 index 249991f8f1f..00000000000 --- a/examples/integrations/neo4j/neo4j-se/pom.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - io.helidon.examples.integrations.neo4j - helidon-examples-integration-neo4j-se - Helidon Integrations Neo4j SE Example - - - io.helidon.examples.integrations.neo4j.se.Main - 5.12.0 - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.media - helidon-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j-metrics - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j-health - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.webclient - helidon-webclient - test - - - - org.neo4j.test - neo4j-harness - ${neo4j-harness.version} - test - - - org.junit.vintage - junit-vintage-engine - - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - - --add-exports=java.base/sun.nio.ch=ALL-UNNAMED - --add-opens=java.base/java.lang=ALL-UNNAMED - --add-opens=java.base/java.lang.reflect=ALL-UNNAMED - --add-opens=java.base/java.io=ALL-UNNAMED - --add-opens=java.base/java.nio=ALL-UNNAMED - --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED - - - - - - diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/Main.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/Main.java deleted file mode 100644 index 5d02f2aac55..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/Main.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.se; - -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.LogManager; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.examples.integrations.neo4j.se.domain.MovieRepository; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.integrations.neo4j.Neo4j; -import io.helidon.integrations.neo4j.health.Neo4jHealthCheck; -import io.helidon.integrations.neo4j.metrics.Neo4jMetricsSupport; -import io.helidon.media.jsonb.JsonbSupport; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import org.neo4j.driver.Driver; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - * @throws IOException if there are problems reading logging properties - */ - public static void main(final String[] args) throws IOException { - startServer(); - } - - /** - * Start the server. - * @return the created WebServer instance - */ - public static Single startServer() { - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - Single server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .addMediaSupport(JsonbSupport.create()) - .build() - .start(); - - server.thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/api/movies"); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - return server; - } - - /** - * Creates new Routing. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - - Neo4j neo4j = Neo4j.create(config.get("neo4j")); - - // registers all metrics - Neo4jMetricsSupport.builder() - .driver(neo4j.driver()) - .build() - .initialize(); - - Neo4jHealthCheck healthCheck = Neo4jHealthCheck.create(neo4j.driver()); - - Driver neo4jDriver = neo4j.driver(); - - MovieService movieService = new MovieService(new MovieRepository(neo4jDriver)); - - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .addReadiness(healthCheck) - .build(); - - return Routing.builder() - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register(movieService) - .build(); - } - - /** - * Configure logging from logging.properties file. - */ - private static void setupLogging() throws IOException { - try (InputStream is = Main.class.getResourceAsStream("/logging.properties")) { - LogManager.getLogManager().readConfiguration(is); - } - } - -} diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/MovieService.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/MovieService.java deleted file mode 100644 index 6e010556b4b..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/MovieService.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.se; - -import io.helidon.examples.integrations.neo4j.se.domain.MovieRepository; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * The Movie service. - * - */ -public class MovieService implements Service { - - private final MovieRepository movieRepository; - - /** - * The movies service. - * @param movieRepository - */ - public MovieService(MovieRepository movieRepository) { - this.movieRepository = movieRepository; - } - - /** - * Main routing done here. - * - * @param rules - */ - @Override - public void update(Routing.Rules rules) { - rules.get("/api/movies", this::findMoviesHandler); - } - - private void findMoviesHandler(ServerRequest request, ServerResponse response) { - response.send(this.movieRepository.findAll()); - } -} diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Actor.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Actor.java deleted file mode 100644 index 7b0bdb2320e..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Actor.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.se.domain; - -import java.util.ArrayList; -import java.util.List; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * The Actor class. - * - * @author Michael Simons - */ -public class Actor { - - private final String name; - - private final List roles; - - /** - * Constructor for actor. - * - * @param name - * @param roles - */ - public Actor(String name, final List roles) { - this.name = name; - this.roles = new ArrayList<>(roles); - } - - public String getName() { - return name; - } - - public List getRoles() { - return roles; - } -} diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Movie.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Movie.java deleted file mode 100644 index 42552be4d6e..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Movie.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.se.domain; - -import java.util.ArrayList; -import java.util.List; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * The Movie class. - * - * @author Michael Simons - */ -public class Movie { - - private final String title; - - private final String description; - - private List actors = new ArrayList<>(); - - private List directors = new ArrayList<>(); - - private Integer released; - - /** - * Constructor for Movie. - * - * @param title - * @param description - */ - public Movie(String title, String description) { - this.title = title; - this.description = description; - } - - public String getTitle() { - return title; - } - - public List getActors() { - return actors; - } - - public void setActors(List actors) { - this.actors = actors; - } - - public String getDescription() { - return description; - } - - public List getDirectors() { - return directors; - } - - public void setDirectorss(List directors) { - this.directors = directors; - } - - public Integer getReleased() { - return released; - } - - public void setReleased(Integer released) { - this.released = released; - } -} diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/MovieRepository.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/MovieRepository.java deleted file mode 100644 index 0e5d9bf79b1..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/MovieRepository.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.neo4j.se.domain; - -import java.util.List; - -import org.neo4j.driver.Driver; -import org.neo4j.driver.Value; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * The Movie repository. - * - * @author Michael Simons - */ -public final class MovieRepository { - - private final Driver driver; - - /** - * Constructor for the repo. - * - * @param driver - */ - public MovieRepository(Driver driver) { - this.driver = driver; - } - - /** - * Returns all the movies. - * @return List with movies - */ - public List findAll(){ - - try (var session = driver.session()) { - - var query = "" - + "match (m:Movie) " - + "match (m) <- [:DIRECTED] - (d:Person) " - + "match (m) <- [r:ACTED_IN] - (a:Person) " - + "return m, collect(d) as directors, collect({name:a.name, roles: r.roles}) as actors"; - - return session.readTransaction(tx -> tx.run(query).list(r -> { - var movieNode = r.get("m").asNode(); - - var directors = r.get("directors").asList(v -> { - var personNode = v.asNode(); - return new Person(personNode.get("born").asInt(), personNode.get("name").asString()); - }); - - var actors = r.get("actors").asList(v -> { - return new Actor(v.get("name").asString(), v.get("roles").asList(Value::asString)); - }); - - var m = new Movie(movieNode.get("title").asString(), movieNode.get("tagline").asString()); - m.setReleased(movieNode.get("released").asInt()); - m.setDirectorss(directors); - m.setActors(actors); - return m; - })); - } - } -} diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Person.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Person.java deleted file mode 100644 index 7a057c6617a..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/Person.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.integrations.neo4j.se.domain; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * The Person class. - * - * @author Michael Simons - */ -public class Person { - - private final String name; - - private Integer born; - - /** - * Constrictor for person. - * @param born - * @param name - */ - public Person(Integer born, String name) { - this.born = born; - this.name = name; - } - - public String getName() { - return name; - } - - public Integer getBorn() { - return born; - } - - public void setBorn(Integer born) { - this.born = born; - } - - @SuppressWarnings("checkstyle:OperatorWrap") - @Override - public String toString() { - return "Person{" + - "name='" + name + '\'' + - ", born=" + born + - '}'; - } -} diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/package-info.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/package-info.java deleted file mode 100644 index efb4e863e8b..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/domain/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Domain objects for movies. - */ -package io.helidon.examples.integrations.neo4j.se.domain; diff --git a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/package-info.java b/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/package-info.java deleted file mode 100644 index 62a2ff870ee..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/java/io/helidon/examples/integrations/neo4j/se/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * SE Neo4j demo application. - *

- * - * @see io.helidon.examples.integrations.neo4j.se.Main - */ -package io.helidon.examples.integrations.neo4j.se; diff --git a/examples/integrations/neo4j/neo4j-se/src/main/resources/application.yaml b/examples/integrations/neo4j/neo4j-se/src/main/resources/application.yaml deleted file mode 100644 index 9103d052e4f..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -server: - port: 8080 - host: 0.0.0.0 - - -neo4j: - uri: bolt://localhost:7687 - authentication: - username: neo4j - password: secret - pool: - metricsEnabled: true diff --git a/examples/integrations/neo4j/neo4j-se/src/main/resources/logging.properties b/examples/integrations/neo4j/neo4j-se/src/main/resources/logging.properties deleted file mode 100644 index aced7e48602..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java b/examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java deleted file mode 100644 index 0b778663818..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.se; - -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.examples.integrations.neo4j.se.Main; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.JsonArray; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.neo4j.harness.Neo4j; -import org.neo4j.harness.Neo4jBuilders; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Main test class for Neo4j Helidon SE quickstarter. - */ -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - - private static Neo4j embeddedDatabaseServer; - - @BeforeAll - static void startTheServer() { - - embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() - .withDisabledServer() - .withFixture(FIXTURE) - .build(); - - System.setProperty("neo4j.uri", embeddedDatabaseServer.boltURI().toString()); - - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - static void stopServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - if (embeddedDatabaseServer != null) { - embeddedDatabaseServer.close(); - } - } - - @Test - void testMovies() { - - JsonArray result = webClient.get() - .path("api/movies") - .request(JsonArray.class) - .await(); - - assertThat(result.getJsonObject(0).getString("title"), is("The Matrix")); - } - - @Test - public void testHealth() { - - WebClientResponse response = webClient.get() - .path("/health") - .request() - .await(); - - assertThat(response.status(), is(Http.Status.OK_200)); - } - - @Test - public void testMetrics() { - WebClientResponse response = webClient.get() - .path("/metrics") - .request() - .await(); - - assertThat(response.status(), is(Http.Status.OK_200)); - } - - static final String FIXTURE = """ - CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'}) - CREATE (Keanu:Person {name:'Keanu Reeves', born:1964}) - CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967}) - CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961}) - CREATE (Hugo:Person {name:'Hugo Weaving', born:1960}) - CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967}) - CREATE (LanaW:Person {name:'Lana Wachowski', born:1965}) - CREATE (JoelS:Person {name:'Joel Silver', born:1952}) - CREATE (KevinB:Person {name:'Kevin Bacon', born:1958}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix), - (LillyW)-[:DIRECTED]->(TheMatrix), - (LanaW)-[:DIRECTED]->(TheMatrix), - (JoelS)-[:PRODUCED]->(TheMatrix) - - CREATE (Emil:Person {name:"Emil Eifrem", born:1978}) - CREATE (Emil)-[:ACTED_IN {roles:["Emil"]}]->(TheMatrix) - - CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded), - (LillyW)-[:DIRECTED]->(TheMatrixReloaded), - (LanaW)-[:DIRECTED]->(TheMatrixReloaded), - (JoelS)-[:PRODUCED]->(TheMatrixReloaded) - - CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, tagline:'Everything that has a beginning has an end'}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions), - (KevinB)-[:ACTED_IN {roles:['Unknown']}]->(TheMatrixRevolutions), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions), - (LillyW)-[:DIRECTED]->(TheMatrixRevolutions), - (LanaW)-[:DIRECTED]->(TheMatrixRevolutions), - (JoelS)-[:PRODUCED]->(TheMatrixRevolutions) - """; -} \ No newline at end of file diff --git a/examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/package-info.java b/examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/package-info.java deleted file mode 100644 index 55429240b5e..00000000000 --- a/examples/integrations/neo4j/neo4j-se/src/test/java/io/helidon/examples/quickstart/se/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Tests for Neo4j Helidon SE app. - */ -package io.helidon.examples.quickstart.se; diff --git a/examples/integrations/neo4j/pom.xml b/examples/integrations/neo4j/pom.xml deleted file mode 100644 index 513a65e124e..00000000000 --- a/examples/integrations/neo4j/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 3.2.7-SNAPSHOT - - io.helidon.examples.integrations.neo4j - helidon-examples-integrations-neo4j-project - Helidon Neo4j Integrations Examples - pom - - - neo4j-mp - neo4j-se - - - diff --git a/examples/integrations/oci/README.md b/examples/integrations/oci/README.md deleted file mode 100644 index ead822ac417..00000000000 --- a/examples/integrations/oci/README.md +++ /dev/null @@ -1 +0,0 @@ -# OCI Java SDK Examples diff --git a/examples/integrations/oci/atp-cdi/README.md b/examples/integrations/oci/atp-cdi/README.md deleted file mode 100644 index 33e8176703c..00000000000 --- a/examples/integrations/oci/atp-cdi/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Helidon ATP MP Examples - -This example demonstrates how user can easily retrieve wallet from their ATP instance running in OCI and use information from that wallet to setup DataSource to do Database operations. - -It requires a running OCI ATP instance. - -Before running the test, make sure to update required properties in `application.yaml` - -- oci.atp.ocid: This is OCID of your running ATP instance. -- oci.atp.walletPassword: password to encrypt the keys inside the wallet. The password must be at least 8 characters long and must include at least 1 letter and either 1 numeric character or 1 special character. -- oracle.ucp.jdbc.PoolDataSource.atp.tnsNetServiceName: netServiceName of your database running inside OCI ATP as can be found in `tnsnames.ora` file. -- oracle.ucp.jdbc.PoolDataSource.atp.user: User to access your database running inside OCI ATP. -- oracle.ucp.jdbc.PoolDataSource.atp.password: Password of user to access your database running inside OCI ATP. - -Once you have updated required properties, you can run the example: - -```shell script -mvn clean install -java -jar ./target/helidon-examples-integrations-oci-atp-cdi.jar -``` - -To verify that, you can retrieve wallet and do database operation: - -```text -http://localhost:8080/atp/wallet -``` - -You should see `Hello world!!` \ No newline at end of file diff --git a/examples/integrations/oci/atp-cdi/pom.xml b/examples/integrations/oci/atp-cdi/pom.xml deleted file mode 100644 index 21f98b54ea0..00000000000 --- a/examples/integrations/oci/atp-cdi/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-atp-cdi - Helidon Examples Integration OCI ATP CDI - CDI integration with OCI ATP. - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-ucp - - - io.helidon.integrations.db - ojdbc - - - com.oracle.database.jdbc - ucp - - - io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-cdi - runtime - - - com.oracle.oci.sdk - oci-java-sdk-database - - - io.helidon.config - helidon-config-yaml-mp - - - org.jboss - jandex - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/AtpResource.java b/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/AtpResource.java deleted file mode 100644 index ceb1d291504..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/AtpResource.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.atp.cdi; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.KeyStore; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; - -import com.oracle.bmc.database.Database; -import com.oracle.bmc.database.model.GenerateAutonomousDatabaseWalletDetails; -import com.oracle.bmc.database.requests.GenerateAutonomousDatabaseWalletRequest; -import com.oracle.bmc.database.responses.GenerateAutonomousDatabaseWalletResponse; -import com.oracle.bmc.http.client.Options; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; -import oracle.security.pki.OraclePKIProvider; -import oracle.ucp.jdbc.PoolDataSource; -import org.eclipse.microprofile.config.inject.ConfigProperty; -/** - * JAX-RS resource - REST API for the atp example. - */ -@Path("/atp") -public class AtpResource { - private static final Logger LOGGER = Logger.getLogger(AtpResource.class.getName()); - - private final Database databaseClient; - private final PoolDataSource atpDataSource; - private final String atpTnsNetServiceName; - - private final String atpOcid; - private final String walletPassword; - - @Inject - AtpResource(Database databaseClient, @Named("atp") PoolDataSource atpDataSource, - @ConfigProperty(name = "oracle.ucp.jdbc.PoolDataSource.atp.tnsNetServiceName") String atpTnsNetServiceName, - @ConfigProperty(name = "oci.atp.ocid") String atpOcid, - @ConfigProperty(name = "oci.atp.walletPassword") String walletPassword) { - this.databaseClient = databaseClient; - this.atpDataSource = Objects.requireNonNull(atpDataSource); - this.atpTnsNetServiceName = atpTnsNetServiceName; - this.atpOcid = atpOcid; - this.walletPassword = walletPassword; - } - - /** - * Generate wallet file for the configured ATP. - * - * @return response containing wallet file - */ - @GET - @Path("/wallet") - public Response generateWallet() { - Options.shouldAutoCloseResponseInputStream(false); - GenerateAutonomousDatabaseWalletResponse walletResponse = - databaseClient.generateAutonomousDatabaseWallet( - GenerateAutonomousDatabaseWalletRequest.builder() - .autonomousDatabaseId(this.atpOcid) - .generateAutonomousDatabaseWalletDetails( - GenerateAutonomousDatabaseWalletDetails.builder() - .password(this.walletPassword) - .build()) - .build()); - - if (walletResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GenerateAutonomousDatabaseWalletResponse is empty"); - return Response.status(Response.Status.NOT_FOUND).build(); - } - - byte[] walletContent = null; - try { - walletContent = walletResponse.getInputStream().readAllBytes(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GenerateAutonomousDatabaseWalletResponse", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - String returnEntity = null; - try { - this.atpDataSource.setSSLContext(getSSLContext(walletContent)); - this.atpDataSource.setURL(getJdbcUrl(walletContent, this.atpTnsNetServiceName)); - try ( - Connection connection = this.atpDataSource.getConnection(); - PreparedStatement ps = connection.prepareStatement("SELECT 'Hello world!!' FROM DUAL"); - ResultSet rs = ps.executeQuery() - ){ - rs.next(); - returnEntity = rs.getString(1); - } - } catch (SQLException e) { - LOGGER.log(Level.SEVERE, "Error setting up DataSource", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - - return Response.status(Response.Status.OK).entity(returnEntity).build(); - } - - /** - * Returns SSLContext based on cwallet.sso in wallet. - * - * @param walletContent - * @return SSLContext - */ - private static SSLContext getSSLContext(byte[] walletContent) throws IllegalStateException { - SSLContext sslContext = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("cwallet.sso")) { - KeyStore keyStore = KeyStore.getInstance("SSO", new OraclePKIProvider()); - keyStore.load(zis, null); - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); - trustManagerFactory.init(keyStore); - keyManagerFactory.init(keyStore, null); - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); - } - zis.closeEntry(); - } - } catch (RuntimeException | Error throwMe) { - throw throwMe; - } catch (Exception e) { - throw new IllegalStateException("Error while getting SSLContext from wallet.", e); - } - return sslContext; - } - - /** - * Returns JDBC URL with connection description for the given service based on tnsnames.ora in wallet. - * - * @param walletContent - * @param tnsNetServiceName - * @return String - */ - private static String getJdbcUrl(byte[] walletContent, String tnsNetServiceName) throws IllegalStateException { - String jdbcUrl = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("tnsnames.ora")) { - jdbcUrl = new String(zis.readAllBytes(), StandardCharsets.UTF_8) - .replaceFirst(tnsNetServiceName + "\\s*=\\s*", "jdbc:oracle:thin:@") - .replaceAll("\\n[^\\n]+", ""); - } - zis.closeEntry(); - } - } catch (IOException e) { - throw new IllegalStateException("Error while getting JDBC URL from wallet.", e); - } - return jdbcUrl; - } -} - diff --git a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/package-info.java b/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/package-info.java deleted file mode 100644 index b8468161b7c..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of integration with OCI ATP in CDI application. - */ -package io.helidon.examples.integrations.oci.atp.cdi; diff --git a/examples/integrations/oci/atp-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/oci/atp-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/oci/atp-cdi/src/main/resources/application.yaml b/examples/integrations/oci/atp-cdi/src/main/resources/application.yaml deleted file mode 100644 index de8655b3d5b..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here - -server: - port: 8080 - -oracle: - ucp: - jdbc: - PoolDataSource: - atp: - connectionFactoryClassName: oracle.jdbc.pool.OracleDataSource - tnsNetServiceName: "${atp.db.tnsNetServiceName}" - user: "${atp.db.user}" - password: "${atp.db.password}" - -oci: - atp: - ocid: "${oci.properties.atp-ocid}" - walletPassword: "${oci.properties.atp-walletPassword}" \ No newline at end of file diff --git a/examples/integrations/oci/atp-cdi/src/main/resources/logging.properties b/examples/integrations/oci/atp-cdi/src/main/resources/logging.properties deleted file mode 100644 index d69a37e024f..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/atp-reactive/README.md b/examples/integrations/oci/atp-reactive/README.md deleted file mode 100644 index 20b402558c1..00000000000 --- a/examples/integrations/oci/atp-reactive/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Helidon ATP Reactive Examples - -This example demonstrates how user can easily retrieve wallet from their ATP instance running in OCI and use information from that wallet to setup DataSource to do Database operations. - -It requires a running OCI ATP instance. - -Before running the test, make sure to update required properties in `application.yaml` - -- oci.atp.ocid: This is OCID of your running ATP instance. -- oci.atp.walletPassword: password to encrypt the keys inside the wallet. The password must be at least 8 characters long and must include at least 1 letter and either 1 numeric character or 1 special character. -- db.tnsNetServiceName: netServiceName of your database running inside OCI ATP as can be found in `tnsnames.ora` file. -- db.userName: User to access your database running inside OCI ATP. -- db.password: Password of user to access your database running inside OCI ATP. - -Once you have updated required properties, you can run the example: - -```shell script -mvn clean install -java -jar ./target/helidon-examples-integrations-oci-atp-reactive.jar -``` - -To verify that, you can retrieve wallet and do database operation: - -```text -http://localhost:8080/atp/wallet -``` - -You should see `Hello world!!` diff --git a/examples/integrations/oci/atp-reactive/pom.xml b/examples/integrations/oci/atp-reactive/pom.xml deleted file mode 100644 index a3e551c5343..00000000000 --- a/examples/integrations/oci/atp-reactive/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-atp-reactive - Helidon Examples Integration OCI ATP Reactive - Reactive integration with OCI ATP. - - - io.helidon.examples.integrations.oci.atp.reactive.OciAtpMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.dbclient - helidon-dbclient - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.integrations.db - ojdbc - - - com.oracle.database.jdbc - ucp - - - io.helidon.config - helidon-config-yaml - - - com.oracle.oci.sdk - oci-java-sdk-database - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/AtpService.java b/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/AtpService.java deleted file mode 100644 index e8d2858d506..00000000000 --- a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/AtpService.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.atp.reactive; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.KeyStore; -import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; - -import io.helidon.common.http.Http; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.jdbc.JdbcDbClientProvider; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import com.oracle.bmc.database.DatabaseAsync; -import com.oracle.bmc.database.model.GenerateAutonomousDatabaseWalletDetails; -import com.oracle.bmc.database.requests.GenerateAutonomousDatabaseWalletRequest; -import com.oracle.bmc.database.responses.GenerateAutonomousDatabaseWalletResponse; -import oracle.jdbc.pool.OracleDataSource; -import oracle.security.pki.OraclePKIProvider; -import oracle.ucp.jdbc.PoolDataSource; -import oracle.ucp.jdbc.PoolDataSourceFactory; - -class AtpService implements Service { - private static final Logger LOGGER = Logger.getLogger(AtpService.class.getName()); - - private final DatabaseAsync databaseAsyncClient; - private final Config config; - - AtpService(DatabaseAsync databaseAsyncClient, Config config) { - this.databaseAsyncClient = databaseAsyncClient; - this.config = config; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/wallet", this::generateWallet); - } - - /** - * Generate wallet file for the configured ATP. - */ - private void generateWallet(ServerRequest req, ServerResponse res) { - OciResponseHandler walletHandler = - new OciResponseHandler<>(); - GenerateAutonomousDatabaseWalletResponse walletResponse = null; - try { - databaseAsyncClient.generateAutonomousDatabaseWallet( - GenerateAutonomousDatabaseWalletRequest.builder() - .autonomousDatabaseId(config.get("oci.atp.ocid").asString().get()) - .generateAutonomousDatabaseWalletDetails( - GenerateAutonomousDatabaseWalletDetails.builder() - .password(config.get("oci.atp.walletPassword").asString().get()) - .build()) - .build(), walletHandler); - walletResponse = walletHandler.waitForCompletion(); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error waiting for GenerateAutonomousDatabaseWalletResponse", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - - if (walletResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GenerateAutonomousDatabaseWalletResponse is empty"); - res.status(Http.Status.NOT_FOUND_404).send(); - return; - } - - byte[] walletContent = null; - try { - walletContent = walletResponse.getInputStream().readAllBytes(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GenerateAutonomousDatabaseWalletResponse", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - - createDbClient(walletContent) - .flatMap(dbClient -> dbClient.execute(exec -> exec.query("SELECT 'Hello world!!' FROM DUAL"))) - .first() - .map(dbRow -> dbRow.column(1).as(String.class)) - .ifEmpty(() -> res.status(404).send()) - .onError(res::send) - .forSingle(res::send); - } - - Single createDbClient(byte[] walletContent) { - PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource(); - try { - pds.setSSLContext(getSSLContext(walletContent)); - pds.setURL(getJdbcUrl(walletContent, config.get("db.tnsNetServiceName") - .as(String.class) - .orElseThrow(() -> new IllegalStateException("Missing tnsNetServiceName!!")))); - pds.setUser(config.get("db.userName").as(String.class).orElse("ADMIN")); - pds.setPassword(config.get("db.password") - .as(String.class) - .orElseThrow(() -> new IllegalStateException("Missing password!!"))); - pds.setConnectionFactoryClassName(OracleDataSource.class.getName()); - } catch (SQLException e) { - LOGGER.log(Level.SEVERE, "Error setting up PoolDataSource", e); - return Single.error(e); - } - return Single.just(new JdbcDbClientProvider().builder() - .connectionPool(() -> { - try { - return pds.getConnection(); - } catch (SQLException e) { - throw new IllegalStateException("Error while setting up new connection", e); - } - }) - .build()); - } - - /** - * Returns SSLContext based on cwallet.sso in wallet. - * - * @return SSLContext - */ - private static SSLContext getSSLContext(byte[] walletContent) throws IllegalStateException { - SSLContext sslContext = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("cwallet.sso")) { - KeyStore keyStore = KeyStore.getInstance("SSO", new OraclePKIProvider()); - keyStore.load(zis, null); - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); - trustManagerFactory.init(keyStore); - keyManagerFactory.init(keyStore, null); - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); - } - zis.closeEntry(); - } - } catch (RuntimeException | Error throwMe) { - throw throwMe; - } catch (Exception e) { - throw new IllegalStateException("Error while getting SSLContext from wallet.", e); - } - return sslContext; - } - - /** - * Returns JDBC URL with connection description for the given service based on tnsnames.ora in wallet. - * - * @param walletContent - * @param tnsNetServiceName - * @return String - */ - private static String getJdbcUrl(byte[] walletContent, String tnsNetServiceName) throws IllegalStateException { - String jdbcUrl = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("tnsnames.ora")) { - jdbcUrl = new String(zis.readAllBytes(), StandardCharsets.UTF_8) - .replaceFirst(tnsNetServiceName + "\\s*=\\s*", "jdbc:oracle:thin:@") - .replaceAll("\\n[^\\n]+", ""); - } - zis.closeEntry(); - } - } catch (IOException e) { - throw new IllegalStateException("Error while getting JDBC URL from wallet.", e); - } - return jdbcUrl; - } -} diff --git a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciAtpMain.java b/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciAtpMain.java deleted file mode 100644 index b7768c4493c..00000000000 --- a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciAtpMain.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.atp.reactive; - -import java.io.IOException; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.database.DatabaseAsync; -import com.oracle.bmc.database.DatabaseAsyncClient; -import com.oracle.bmc.model.BmcException; - -/** - * Main class of the example. - * This example sets up a web server to serve REST API to retrieve ATP wallet. - */ -public final class OciAtpMain { - /** - * Cannot be instantiated. - */ - private OciAtpMain() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) throws IOException { - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // this requires OCI configuration in the usual place - // ~/.oci/config - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(ConfigFileReader.parseDefault()); - DatabaseAsync databaseAsyncClient = DatabaseAsyncClient.builder().build(authProvider); - - // Prepare routing for the server - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(Routing.builder() - .register("/atp", new AtpService(databaseAsyncClient, config)) - // OCI SDK error handling - .error(BmcException.class, (req, res, ex) -> res.status(ex.getStatusCode()) - .send(ex.getMessage()))) - .build(); - - // Start the server and print some info. - server.start().thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/"); - }); - - // Server threads are not daemon. NO need to block. Just react. - server.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - } -} diff --git a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciResponseHandler.java b/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciResponseHandler.java deleted file mode 100644 index 0eac2a44fa5..00000000000 --- a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/OciResponseHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.atp.reactive; - -import java.util.concurrent.CountDownLatch; - -import com.oracle.bmc.responses.AsyncHandler; - -final class OciResponseHandler implements AsyncHandler { - private OUT item; - private Throwable failed = null; - private CountDownLatch latch = new CountDownLatch(1); - - protected OUT waitForCompletion() throws Exception { - latch.await(); - if (failed != null) { - if (failed instanceof Exception) { - throw (Exception) failed; - } - throw (Error) failed; - } - return item; - } - - @Override - public void onSuccess(IN request, OUT response) { - item = response; - latch.countDown(); - } - - @Override - public void onError(IN request, Throwable error) { - failed = error; - latch.countDown(); - } -} diff --git a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/package-info.java b/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/package-info.java deleted file mode 100644 index ee7800316ed..00000000000 --- a/examples/integrations/oci/atp-reactive/src/main/java/io/helidon/examples/integrations/oci/atp/reactive/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of integration with OCI ATP in reactive application. - */ -package io.helidon.examples.integrations.oci.atp.reactive; diff --git a/examples/integrations/oci/atp-reactive/src/main/resources/application.yaml b/examples/integrations/oci/atp-reactive/src/main/resources/application.yaml deleted file mode 100644 index 156f26ed159..00000000000 --- a/examples/integrations/oci/atp-reactive/src/main/resources/application.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here - -server: - port: 8080 - -db: - userName: "${atp.db.userName}" - password: "${atp.db.password}" - tnsNetServiceName: "${atp.db.tnsNetServiceName}" - -oci: - atp: - ocid: "${oci.properties.atp-ocid}" - walletPassword: "${oci.properties.atp-walletPassword}" diff --git a/examples/integrations/oci/atp-reactive/src/main/resources/logging.properties b/examples/integrations/oci/atp-reactive/src/main/resources/logging.properties deleted file mode 100644 index d69a37e024f..00000000000 --- a/examples/integrations/oci/atp-reactive/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/metrics-reactive/pom.xml b/examples/integrations/oci/metrics-reactive/pom.xml deleted file mode 100644 index 62d8eac1d13..00000000000 --- a/examples/integrations/oci/metrics-reactive/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - - - io.helidon.examples.integrations.oci.telemetry.reactive.OciMetricsMain - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-metrics-reactive - Helidon Examples Integration OCI Metrics Reactive - Reactive integration with OCI Metrics. - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - com.oracle.oci.sdk - oci-java-sdk-monitoring - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/OciMetricsMain.java b/examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/OciMetricsMain.java deleted file mode 100644 index 400edcd731a..00000000000 --- a/examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/OciMetricsMain.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.telemetry.reactive; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.monitoring.MonitoringAsync; -import com.oracle.bmc.monitoring.MonitoringAsyncClient; -import com.oracle.bmc.monitoring.model.Datapoint; -import com.oracle.bmc.monitoring.model.FailedMetricRecord; -import com.oracle.bmc.monitoring.model.MetricDataDetails; -import com.oracle.bmc.monitoring.model.PostMetricDataDetails; -import com.oracle.bmc.monitoring.model.PostMetricDataResponseDetails; -import com.oracle.bmc.monitoring.requests.PostMetricDataRequest; -import com.oracle.bmc.monitoring.responses.PostMetricDataResponse; -import com.oracle.bmc.responses.AsyncHandler; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * OCI Metrics example. - */ -public final class OciMetricsMain { - - private OciMetricsMain() { - } - - /** - * Main method. - * @param args ignored - */ - public static void main(String[] args) throws Exception { - LogConfig.configureRuntime(); - // as I cannot share my configuration of OCI, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - // this requires OCI configuration in the usual place - // ~/.oci/config - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(ConfigFileReader.parseDefault()); - MonitoringAsync monitoringAsyncClient = new MonitoringAsyncClient(authProvider); - monitoringAsyncClient.setEndpoint(monitoringAsyncClient.getEndpoint().replace("telemetry.", "telemetry-ingestion.")); - - PostMetricDataRequest postMetricDataRequest = PostMetricDataRequest.builder() - .postMetricDataDetails(getPostMetricDataDetails(config)) - .build(); - /* - * Invoke the API call. I use .await() to block the call, as otherwise our - * main method would finish without waiting for the response. - * In a real reactive application, this should not be done (as you would write the response - * to a server response or use other reactive/non-blocking APIs). - */ - ResponseHandler monitoringHandler = - new ResponseHandler<>(); - monitoringAsyncClient.postMetricData(postMetricDataRequest, monitoringHandler); - PostMetricDataResponse postMetricDataResponse = monitoringHandler.waitForCompletion(); - PostMetricDataResponseDetails postMetricDataResponseDetails = postMetricDataResponse.getPostMetricDataResponseDetails(); - int count = postMetricDataResponseDetails.getFailedMetricsCount(); - System.out.println("Failed count: " + count); - if (count > 0) { - System.out.println("Failed metrics:"); - for (FailedMetricRecord failedMetric : postMetricDataResponseDetails.getFailedMetrics()) { - System.out.println("\t" + failedMetric.getMessage() + ": " + failedMetric.getMetricData()); - } - } - } - - private static PostMetricDataDetails getPostMetricDataDetails(Config config) { - String compartmentId = config.get("oci.metrics.compartment-ocid").asString().get(); - Instant now = Instant.now(); - return PostMetricDataDetails.builder() - .metricData( - Arrays.asList( - MetricDataDetails.builder() - .compartmentId(compartmentId) - // Add a few data points to see something in the console - .datapoints( - Arrays.asList( - Datapoint.builder() - .timestamp(Date.from( - now.minus(10, ChronoUnit.SECONDS) - )) - .value(101.00) - .build(), - Datapoint.builder() - .timestamp(Date.from(now)) - .value(149.00) - .build() - )) - .dimensions( - makeMap("resourceId", "myresourceid", - "unit", "cm")) - .name("my_app.jump") - .namespace("helidon_examples") - .build() - )) - .batchAtomicity(PostMetricDataDetails.BatchAtomicity.NonAtomic).build(); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } - - private static Map makeMap(String... data) { - Map map = new HashMap<>(); - for (int i = 0; i < data.length; i += 2) { - map.put(data[i], data[i + 1]); - } - return map; - } - - private static class ResponseHandler implements AsyncHandler { - private OUT item; - private Throwable failed = null; - private CountDownLatch latch = new CountDownLatch(1); - - private OUT waitForCompletion() throws Exception { - latch.await(); - if (failed != null) { - if (failed instanceof Exception) { - throw (Exception) failed; - } - throw (Error) failed; - } - return item; - } - - @Override - public void onSuccess(IN request, OUT response) { - item = response; - latch.countDown(); - } - - @Override - public void onError(IN request, Throwable error) { - failed = error; - latch.countDown(); - } - } -} diff --git a/examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/package-info.java b/examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/package-info.java deleted file mode 100644 index 5e3c842230a..00000000000 --- a/examples/integrations/oci/metrics-reactive/src/main/java/io/helidon/examples/integrations/oci/telemetry/reactive/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example using OCI metrics reactive API. - */ -package io.helidon.examples.integrations.oci.telemetry.reactive; diff --git a/examples/integrations/oci/metrics-reactive/src/main/resources/application.yaml b/examples/integrations/oci/metrics-reactive/src/main/resources/application.yaml deleted file mode 100644 index d9304c7641e..00000000000 --- a/examples/integrations/oci/metrics-reactive/src/main/resources/application.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here -oci: - metrics: - compartment-ocid: "${oci.properties.compartment-ocid}" - diff --git a/examples/integrations/oci/metrics-reactive/src/main/resources/logging.properties b/examples/integrations/oci/metrics-reactive/src/main/resources/logging.properties deleted file mode 100644 index d0317654f47..00000000000 --- a/examples/integrations/oci/metrics-reactive/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/oci/objectstorage-cdi/pom.xml b/examples/integrations/oci/objectstorage-cdi/pom.xml deleted file mode 100644 index 36b3704da77..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-objectstorage-cdi - Helidon Examples Integration OCI Object Storage CDI - CDI integration with OCI Object Storage. - - - io.helidon.examples.integrations.oci.objectstorage.cdi.ObjectStorageCdiMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-cdi - - - com.oracle.oci.sdk - oci-java-sdk-objectstorage - - - io.helidon.config - helidon-config-yaml-mp - - - org.jboss - jandex - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageCdiMain.java b/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageCdiMain.java deleted file mode 100644 index 4d99c4a9ebd..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageCdiMain.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.objectstorage.cdi; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.microprofile.cdi.Main; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.eclipse.microprofile.config.spi.ConfigSource; - -/** - * Main class of the example. - * This is only used to merge configuration from home directory with the one embedded on classpath. - */ -public final class ObjectStorageCdiMain { - private ObjectStorageCdiMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - ConfigProviderResolver configProvider = ConfigProviderResolver.instance(); - - Config mpConfig = configProvider.getBuilder() - .addDefaultSources() - .withSources(examplesConfig()) - .addDiscoveredSources() - .addDiscoveredConverters() - .build(); - - // configure - configProvider.registerConfig(mpConfig, null); - - // start CDI - Main.main(args); - } - - private static ConfigSource[] examplesConfig() { - Path path = Paths.get(System.getProperty("user.home") + "/helidon/conf/examples.yaml"); - if (Files.exists(path)) { - return new ConfigSource[] {YamlMpConfigSource.create(path)}; - } - return new ConfigSource[0]; - } -} diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageResource.java b/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageResource.java deleted file mode 100644 index 905e3e6cdef..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageResource.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.objectstorage.cdi; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; - -import com.oracle.bmc.objectstorage.ObjectStorage; -import com.oracle.bmc.objectstorage.requests.DeleteObjectRequest; -import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; -import com.oracle.bmc.objectstorage.requests.GetObjectRequest; -import com.oracle.bmc.objectstorage.requests.PutObjectRequest; -import com.oracle.bmc.objectstorage.responses.DeleteObjectResponse; -import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse; -import com.oracle.bmc.objectstorage.responses.GetObjectResponse; -import com.oracle.bmc.objectstorage.responses.PutObjectResponse; -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * JAX-RS resource - REST API for the objecstorage example. - */ -@Path("/files") -public class ObjectStorageResource { - private static final Logger LOGGER = Logger.getLogger(ObjectStorageResource.class.getName()); - private final ObjectStorage objectStorageClient; - private final String namespaceName; - private final String bucketName; - - @Inject - ObjectStorageResource(ObjectStorage objectStorageClient, - @ConfigProperty(name = "oci.objectstorage.bucketName") - String bucketName) { - this.objectStorageClient = objectStorageClient; - this.bucketName = bucketName; - GetNamespaceResponse namespaceResponse = - this.objectStorageClient.getNamespace(GetNamespaceRequest.builder().build()); - this.namespaceName = namespaceResponse.getValue(); - } - - /** - * Download a file from object storage. - * - * @param fileName name of the object - * @return response - */ - @GET - @Path("/file/{file-name}") - public Response download(@PathParam("file-name") String fileName) { - GetObjectResponse getObjectResponse = - objectStorageClient.getObject( - GetObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .build()); - - if (getObjectResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GetObjectResponse is empty"); - return Response.status(Response.Status.NOT_FOUND).build(); - } - - try (InputStream fileStream = getObjectResponse.getInputStream()) { - byte[] objectContent = fileStream.readAllBytes(); - Response.ResponseBuilder ok = Response.ok(objectContent) - .header(Http.Header.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"") - .header("opc-request-id", getObjectResponse.getOpcRequestId()) - .header("request-id", getObjectResponse.getOpcClientRequestId()) - .header(Http.Header.CONTENT_LENGTH, getObjectResponse.getContentLength()); - - return ok.build(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GetObjectResponse", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - } - - /** - * Upload a file to object storage. - * - * @param fileName name of the object - * @return response - */ - @POST - @Path("/file/{fileName}") - public Response upload(@PathParam("fileName") String fileName) { - - PutObjectRequest putObjectRequest = null; - try (InputStream stream = new FileInputStream(System.getProperty("user.dir") + File.separator + fileName)) { - byte[] contents = stream.readAllBytes(); - putObjectRequest = - PutObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .putObjectBody(new ByteArrayInputStream(contents)) - .contentLength(Long.valueOf(contents.length)) - .build(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error creating PutObjectRequest", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - PutObjectResponse putObjectResponse = objectStorageClient.putObject(putObjectRequest); - - Response.ResponseBuilder ok = Response.ok() - .header("opc-request-id", putObjectResponse.getOpcRequestId()) - .header("request-id", putObjectResponse.getOpcClientRequestId()); - - return ok.build(); - } - - /** - * Delete a file from object storage. - * - * @param fileName object name - * @return response - */ - @DELETE - @Path("/file/{file-name}") - public Response delete(@PathParam("file-name") String fileName) { - DeleteObjectResponse deleteObjectResponse = objectStorageClient.deleteObject(DeleteObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .build()); - Response.ResponseBuilder ok = Response.ok() - .header("opc-request-id", deleteObjectResponse.getOpcRequestId()) - .header("request-id", deleteObjectResponse.getOpcClientRequestId()); - - return ok.build(); - } -} diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/package-info.java b/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/package-info.java deleted file mode 100644 index d2e98404d0f..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of integration with OCI object storage in a CDI application. - */ -package io.helidon.examples.integrations.oci.objectstorage.cdi; diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/oci/objectstorage-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/resources/application.yaml b/examples/integrations/oci/objectstorage-cdi/src/main/resources/application.yaml deleted file mode 100644 index f0b991ad95b..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 8080 - -# -# The following properties under oci are accessed by Helidon. Values -# under oci.properties.* are read from ~/helidon/conf/examples.yaml. -# -oci: - objectstorage: - bucketName: "${oci.properties.objectstorage-bucketName}" diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/resources/logging.properties b/examples/integrations/oci/objectstorage-cdi/src/main/resources/logging.properties deleted file mode 100644 index d69a37e024f..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/objectstorage-reactive/pom.xml b/examples/integrations/oci/objectstorage-reactive/pom.xml deleted file mode 100644 index c54d42fd32c..00000000000 --- a/examples/integrations/oci/objectstorage-reactive/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-objectstorage-reactive - Helidon Examples Integration OCI Object Storage Reactive - Reactive integration with OCI Object Storage. - - - io.helidon.examples.integrations.oci.objecstorage.reactive.OciObjectStorageMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - com.oracle.oci.sdk - oci-java-sdk-objectstorage - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/ObjectStorageService.java b/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/ObjectStorageService.java deleted file mode 100644 index 144abe7fa1f..00000000000 --- a/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/ObjectStorageService.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.objecstorage.reactive; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import com.oracle.bmc.objectstorage.ObjectStorageAsync; -import com.oracle.bmc.objectstorage.model.RenameObjectDetails; -import com.oracle.bmc.objectstorage.requests.DeleteObjectRequest; -import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; -import com.oracle.bmc.objectstorage.requests.GetObjectRequest; -import com.oracle.bmc.objectstorage.requests.PutObjectRequest; -import com.oracle.bmc.objectstorage.requests.RenameObjectRequest; -import com.oracle.bmc.objectstorage.responses.DeleteObjectResponse; -import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse; -import com.oracle.bmc.objectstorage.responses.GetObjectResponse; -import com.oracle.bmc.objectstorage.responses.PutObjectResponse; -import com.oracle.bmc.objectstorage.responses.RenameObjectResponse; -import com.oracle.bmc.responses.AsyncHandler; - -class ObjectStorageService implements Service { - private static final Logger LOGGER = Logger.getLogger(ObjectStorageService.class.getName()); - private final ObjectStorageAsync objectStorageAsyncClient; - private final String bucketName; - private final String namespaceName; - - ObjectStorageService(ObjectStorageAsync objectStorageAsyncClient, String bucketName) throws Exception { - this.objectStorageAsyncClient = objectStorageAsyncClient; - this.bucketName = bucketName; - ResponseHandler namespaceHandler = - new ResponseHandler<>(); - this.objectStorageAsyncClient.getNamespace(GetNamespaceRequest.builder().build(), namespaceHandler); - GetNamespaceResponse namespaceResponse = namespaceHandler.waitForCompletion(); - this.namespaceName = namespaceResponse.getValue(); - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/file/{file-name}", this::download) - .post("/file/{file-name}", this::upload) - .delete("/file/{file-name}", this::delete) - .get("/rename/{old-name}/{new-name}", this::rename); - } - - private void delete(ServerRequest req, ServerResponse res) { - String objectName = req.path().param("file-name"); - - ResponseHandler deleteObjectHandler = - new ResponseHandler<>(); - - objectStorageAsyncClient.deleteObject(DeleteObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(objectName).build(), deleteObjectHandler); - try { - DeleteObjectResponse deleteObjectResponse = deleteObjectHandler.waitForCompletion(); - res.status(Http.Status.OK_200) - .send(); - return; - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error deleting object", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - } - - private void rename(ServerRequest req, ServerResponse res) { - String oldName = req.path().param("old-name"); - String newName = req.path().param("new-name"); - - RenameObjectRequest renameObjectRequest = RenameObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .renameObjectDetails(RenameObjectDetails.builder() - .newName(newName) - .sourceName(oldName) - .build()) - .build(); - - ResponseHandler renameObjectHandler = - new ResponseHandler<>(); - - try { - objectStorageAsyncClient.renameObject(renameObjectRequest, renameObjectHandler); - RenameObjectResponse renameObjectResponse = renameObjectHandler.waitForCompletion(); - res.status(Http.Status.OK_200) - .send(); - return; - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error renaming object", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - } - - private void upload(ServerRequest req, ServerResponse res) { - String objectName = req.path().param("file-name"); - PutObjectRequest putObjectRequest = null; - try (InputStream stream = new FileInputStream(System.getProperty("user.dir") + File.separator + objectName)) { - byte[] contents = stream.readAllBytes(); - putObjectRequest = - PutObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(objectName) - .putObjectBody(new ByteArrayInputStream(contents)) - .contentLength(Long.valueOf(contents.length)) - .build(); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error creating PutObjectRequest", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - - ResponseHandler putObjectHandler = - new ResponseHandler<>(); - - try { - objectStorageAsyncClient.putObject(putObjectRequest, putObjectHandler); - PutObjectResponse putObjectResponse = putObjectHandler.waitForCompletion(); - res.status(Http.Status.OK_200).send(); - return; - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error uploading object", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - } - - private void download(ServerRequest req, ServerResponse res) { - String objectName = req.path().param("file-name"); - ResponseHandler objectHandler = - new ResponseHandler<>(); - GetObjectRequest getObjectRequest = - GetObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(objectName) - .build(); - GetObjectResponse getObjectResponse = null; - try { - objectStorageAsyncClient.getObject(getObjectRequest, objectHandler); - getObjectResponse = objectHandler.waitForCompletion(); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error getting object", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - - if (getObjectResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GetObjectResponse is empty"); - res.status(Http.Status.NOT_FOUND_404).send(); - return; - } - - try (InputStream fileStream = getObjectResponse.getInputStream()) { - byte[] objectContent = fileStream.readAllBytes(); - res.addHeader(Http.Header.CONTENT_DISPOSITION, "attachment; filename=\"" + objectName + "\"") - .status(Http.Status.OK_200).send(objectContent); - return; - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GetObjectResponse", e); - res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - } - - private static class ResponseHandler implements AsyncHandler { - private OUT item; - private Throwable failed = null; - private CountDownLatch latch = new CountDownLatch(1); - - private OUT waitForCompletion() throws Exception { - latch.await(); - if (failed != null) { - if (failed instanceof Exception) { - throw (Exception) failed; - } - throw (Error) failed; - } - return item; - } - - @Override - public void onSuccess(IN request, OUT response) { - item = response; - latch.countDown(); - } - - @Override - public void onError(IN request, Throwable error) { - failed = error; - latch.countDown(); - } - } -} diff --git a/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/OciObjectStorageMain.java b/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/OciObjectStorageMain.java deleted file mode 100644 index 81be8ef9bb4..00000000000 --- a/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/OciObjectStorageMain.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.objecstorage.reactive; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.model.BmcException; -import com.oracle.bmc.objectstorage.ObjectStorageAsync; -import com.oracle.bmc.objectstorage.ObjectStorageAsyncClient; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of the example. - * This example sets up a web server to serve REST API to upload/download/delete objects. - */ -public final class OciObjectStorageMain { - private OciObjectStorageMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) throws Exception { - LogConfig.configureRuntime(); - // as I cannot share my configuration of OCI, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - Config ociConfig = config.get("oci"); - - // this requires OCI configuration in the usual place - // ~/.oci/config - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(ConfigFileReader.parseDefault()); - ObjectStorageAsync objectStorageAsyncClient = new ObjectStorageAsyncClient(authProvider); - - // the following parameters are required - String bucketName = ociConfig.get("objectstorage").get("bucketName").asString().get(); - - WebServer.builder() - .config(config.get("server")) - .routing(Routing.builder() - .register("/files", new ObjectStorageService(objectStorageAsyncClient, bucketName)) - // OCI SDK error handling - .error(BmcException.class, (req, res, ex) -> res.status(ex.getStatusCode()) - .send(ex.getMessage()))) - .build() - .start() - .await(); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/package-info.java b/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/package-info.java deleted file mode 100644 index 3bda523337e..00000000000 --- a/examples/integrations/oci/objectstorage-reactive/src/main/java/io/helidon/examples/integrations/oci/objecstorage/reactive/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of integration with OCI object storage in reactive application. - */ -package io.helidon.examples.integrations.oci.objecstorage.reactive; diff --git a/examples/integrations/oci/objectstorage-reactive/src/main/resources/application.yaml b/examples/integrations/oci/objectstorage-reactive/src/main/resources/application.yaml deleted file mode 100644 index 4c07c154bc6..00000000000 --- a/examples/integrations/oci/objectstorage-reactive/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here - -server: - port: 8080 - -oci: - objectstorage: - bucketName: "${oci.properties.objectstorage-bucketName}" diff --git a/examples/integrations/oci/objectstorage-reactive/src/main/resources/logging.properties b/examples/integrations/oci/objectstorage-reactive/src/main/resources/logging.properties deleted file mode 100644 index d69a37e024f..00000000000 --- a/examples/integrations/oci/objectstorage-reactive/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/pom.xml b/examples/integrations/oci/pom.xml deleted file mode 100644 index c9396d8e050..00000000000 --- a/examples/integrations/oci/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 3.2.7-SNAPSHOT - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-project - pom - Helidon Examples Integration OCI - Examples of integration with OCI (Oracle Cloud). - - - atp-reactive - atp-cdi - metrics-reactive - objectstorage-reactive - objectstorage-cdi - vault-reactive - vault-cdi - - - diff --git a/examples/integrations/oci/vault-cdi/pom.xml b/examples/integrations/oci/vault-cdi/pom.xml deleted file mode 100644 index 9544af4cd3c..00000000000 --- a/examples/integrations/oci/vault-cdi/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-vault-cdi - Helidon Examples Integration OCI Object Storage CDI - CDI integration with OCI Object Storage. - - - io.helidon.examples.integrations.oci.vault.cdi.VaultCdiMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-cdi - - - com.oracle.oci.sdk - oci-java-sdk-keymanagement - - - com.oracle.oci.sdk - oci-java-sdk-secrets - - - com.oracle.oci.sdk - oci-java-sdk-vault - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/CryptoClientProducer.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/CryptoClientProducer.java deleted file mode 100644 index 5050eb59b09..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/CryptoClientProducer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.vault.cdi; - -import com.oracle.bmc.keymanagement.KmsCryptoClient; -import com.oracle.bmc.keymanagement.KmsCryptoClientBuilder; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * KMS crypto client (used for encryption, decryption and signatures) requires additional configuration, that cannot - * be done automatically by the SDK. - */ -@ApplicationScoped -class CryptoClientProducer { - private final String cryptoEndpoint; - - @Inject - CryptoClientProducer(@ConfigProperty(name = "app.vault.cryptographic-endpoint") - String cryptoEndpoint) { - this.cryptoEndpoint = cryptoEndpoint; - } - - @Produces - KmsCryptoClientBuilder clientBuilder() { - return KmsCryptoClient.builder() - .endpoint(cryptoEndpoint); - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/ErrorHandlerProvider.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/ErrorHandlerProvider.java deleted file mode 100644 index a6b67e6ff22..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/ErrorHandlerProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.vault.cdi; - -import com.oracle.bmc.model.BmcException; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; - -/** - * Maps SDK errors to HTTP errors, as otherwise any exception is manifested as an internal server error. - * This mapper is not part of integration with OCI SDK, as each application may require a different entity format. - * This mapper simply uses the response code as HTTP status code, and error message as entity. - */ -@Provider -class ErrorHandlerProvider implements ExceptionMapper { - @Override - public Response toResponse(BmcException e) { - return Response.status(e.getStatusCode()) - .entity(e.getMessage()) - .build(); - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultCdiMain.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultCdiMain.java deleted file mode 100644 index ce92665f14e..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultCdiMain.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.integrations.oci.vault.cdi; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.microprofile.cdi.Main; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.eclipse.microprofile.config.spi.ConfigSource; - -/** - * Main class of the example. - * Used only to set up configuration. - */ -public final class VaultCdiMain { - private VaultCdiMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - ConfigProviderResolver configProvider = ConfigProviderResolver.instance(); - - Config mpConfig = configProvider.getBuilder() - .addDefaultSources() - .withSources(examplesConfig()) - .addDiscoveredSources() - .addDiscoveredConverters() - .build(); - - // configure - configProvider.registerConfig(mpConfig, null); - - // start CDI - Main.main(args); - } - - private static ConfigSource[] examplesConfig() { - Path path = Paths.get(System.getProperty("user.home") + "/helidon/conf/examples.yaml"); - if (Files.exists(path)) { - return new ConfigSource[] {YamlMpConfigSource.create(path)}; - } - return new ConfigSource[0]; - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultResource.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultResource.java deleted file mode 100644 index fdeac30e50b..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultResource.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.vault.cdi; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Date; - -import io.helidon.common.Base64Value; - -import com.oracle.bmc.keymanagement.KmsCrypto; -import com.oracle.bmc.keymanagement.model.DecryptDataDetails; -import com.oracle.bmc.keymanagement.model.EncryptDataDetails; -import com.oracle.bmc.keymanagement.model.SignDataDetails; -import com.oracle.bmc.keymanagement.model.VerifyDataDetails; -import com.oracle.bmc.keymanagement.requests.DecryptRequest; -import com.oracle.bmc.keymanagement.requests.EncryptRequest; -import com.oracle.bmc.keymanagement.requests.SignRequest; -import com.oracle.bmc.keymanagement.requests.VerifyRequest; -import com.oracle.bmc.secrets.Secrets; -import com.oracle.bmc.secrets.model.Base64SecretBundleContentDetails; -import com.oracle.bmc.secrets.model.SecretBundleContentDetails; -import com.oracle.bmc.secrets.requests.GetSecretBundleRequest; -import com.oracle.bmc.vault.Vaults; -import com.oracle.bmc.vault.model.Base64SecretContentDetails; -import com.oracle.bmc.vault.model.CreateSecretDetails; -import com.oracle.bmc.vault.model.ScheduleSecretDeletionDetails; -import com.oracle.bmc.vault.model.SecretContentDetails; -import com.oracle.bmc.vault.requests.CreateSecretRequest; -import com.oracle.bmc.vault.requests.ScheduleSecretDeletionRequest; -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.InternalServerErrorException; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * JAX-RS resource - REST API of the example. - */ -@Path("/vault") -public class VaultResource { - private final Secrets secrets; - private final KmsCrypto crypto; - private final Vaults vaults; - private final String vaultOcid; - private final String compartmentOcid; - private final String encryptionKeyOcid; - private final String signatureKeyOcid; - - @Inject - VaultResource(Secrets secrets, - KmsCrypto crypto, - Vaults vaults, - @ConfigProperty(name = "app.vault.vault-ocid") - String vaultOcid, - @ConfigProperty(name = "app.vault.compartment-ocid") - String compartmentOcid, - @ConfigProperty(name = "app.vault.encryption-key-ocid") - String encryptionKeyOcid, - @ConfigProperty(name = "app.vault.signature-key-ocid") - String signatureKeyOcid) { - this.secrets = secrets; - this.crypto = crypto; - this.vaults = vaults; - this.vaultOcid = vaultOcid; - this.compartmentOcid = compartmentOcid; - this.encryptionKeyOcid = encryptionKeyOcid; - this.signatureKeyOcid = signatureKeyOcid; - } - - /** - * Encrypt a string. - * - * @param secret secret to encrypt - * @return cipher text - */ - @GET - @Path("/encrypt/{text}") - public String encrypt(@PathParam("text") String secret) { - return crypto.encrypt(EncryptRequest.builder() - .encryptDataDetails(EncryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .plaintext(Base64Value.create(secret).toBase64()) - .build()) - .build()) - .getEncryptedData() - .getCiphertext(); - } - - /** - * Decrypt a cipher text. - * - * @param cipherText cipher text to decrypt - * @return original secret - */ - @GET - @Path("/decrypt/{text: .*}") - public String decrypt(@PathParam("text") String cipherText) { - return Base64Value.createFromEncoded(crypto.decrypt(DecryptRequest.builder() - .decryptDataDetails(DecryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .ciphertext(cipherText) - .build()) - .build()) - .getDecryptedData() - .getPlaintext()) - .toDecodedString(); - } - - /** - * Sign data. - * - * @param dataToSign data to sign (must be a String) - * @return signature text - */ - @GET - @Path("/sign/{text}") - public String sign(@PathParam("text") String dataToSign) { - return crypto.sign(SignRequest.builder() - .signDataDetails(SignDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(SignDataDetails.SigningAlgorithm.Sha224RsaPkcsPss) - .message(Base64Value.create(dataToSign).toBase64()) - .build()) - .build()) - .getSignedData() - .getSignature(); - } - - /** - * Verify a signature. The base64 encoded signature is the entity - * - * @param dataToVerify data that was signed - * @param signature signature text - * @return whether the signature is valid or not - */ - @POST - @Path("/verify/{text}") - public String verify(@PathParam("text") String dataToVerify, - String signature) { - VerifyDataDetails.SigningAlgorithm algorithm = VerifyDataDetails.SigningAlgorithm.Sha224RsaPkcsPss; - - boolean valid = crypto.verify(VerifyRequest.builder() - .verifyDataDetails(VerifyDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(algorithm) - .message(Base64Value.create(dataToVerify).toBase64()) - .signature(signature) - .build()) - .build()) - .getVerifiedData() - .getIsSignatureValid(); - - return valid ? "Signature valid" : "Signature not valid"; - } - - /** - * Get secret content from Vault. - * - * @param secretOcid OCID of the secret to get - * @return content of the secret - */ - @GET - @Path("/secret/{id}") - public String getSecret(@PathParam("id") String secretOcid) { - SecretBundleContentDetails content = secrets.getSecretBundle(GetSecretBundleRequest.builder() - .secretId(secretOcid) - .build()) - .getSecretBundle() - .getSecretBundleContent(); - - if (content instanceof Base64SecretBundleContentDetails) { - // the only supported type - return Base64Value.createFromEncoded(((Base64SecretBundleContentDetails) content).getContent()).toDecodedString(); - } else { - throw new InternalServerErrorException("Invalid secret content type"); - } - } - - /** - * Delete a secret from Vault. - * This operation actually marks a secret for deletion, and the minimal time is 30 days. - * - * @param secretOcid OCID of the secret to delete - * @return short message - */ - @DELETE - @Path("/secret/{id}") - public String deleteSecret(@PathParam("id") String secretOcid) { - // has to be for quite a long period of time - did not work with less than 30 days - Date deleteTime = Date.from(Instant.now().plus(30, ChronoUnit.DAYS)); - - vaults.scheduleSecretDeletion(ScheduleSecretDeletionRequest.builder() - .secretId(secretOcid) - .scheduleSecretDeletionDetails(ScheduleSecretDeletionDetails.builder() - .timeOfDeletion(deleteTime) - .build()) - .build()); - - return "Secret " + secretOcid + " was marked for deletion"; - } - - /** - * Create a new secret. - * - * @param name name of the secret - * @param secretText secret content - * @return OCID of the created secret - */ - @POST - @Path("/secret/{name}") - public String createSecret(@PathParam("name") String name, - String secretText) { - SecretContentDetails content = Base64SecretContentDetails.builder() - .content(Base64Value.create(secretText).toBase64()) - .build(); - - return vaults.createSecret(CreateSecretRequest.builder() - .createSecretDetails(CreateSecretDetails.builder() - .secretName(name) - .vaultId(vaultOcid) - .compartmentId(compartmentOcid) - .keyId(encryptionKeyOcid) - .secretContent(content) - .build()) - .build()) - .getSecret() - .getId(); - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/package-info.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/package-info.java deleted file mode 100644 index 80a511eaad0..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of OCI Vault integration in CDI. - */ -package io.helidon.examples.integrations.oci.vault.cdi; diff --git a/examples/integrations/oci/vault-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/oci/vault-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/oci/vault-cdi/src/main/resources/application.yaml b/examples/integrations/oci/vault-cdi/src/main/resources/application.yaml deleted file mode 100644 index 3ea5b75de39..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 8080 - -# -# The following properties under oci are accessed by Helidon. Values -# under oci.properties.* are read from ~/helidon/conf/examples.yaml. -# -app: - vault: - # Vault OCID (the vault you want to use for this example) - vault-ocid: "${oci.properties.vault-ocid}" - compartment-ocid: "${oci.properties.compartment-ocid}" - encryption-key-ocid: "${oci.properties.vault-key-ocid}" - signature-key-ocid: "${oci.properties.vault-rsa-key-ocid}" - cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" diff --git a/examples/integrations/oci/vault-cdi/src/main/resources/logging.properties b/examples/integrations/oci/vault-cdi/src/main/resources/logging.properties deleted file mode 100644 index d0317654f47..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/oci/vault-reactive/pom.xml b/examples/integrations/oci/vault-reactive/pom.xml deleted file mode 100644 index 81245fe8569..00000000000 --- a/examples/integrations/oci/vault-reactive/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-vault-reactive - Helidon Examples Integration OCI Vault Reactive - Reactive integration with OCI Vault. - - - io.helidon.examples.integrations.oci.vault.reactive.OciVaultMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - com.oracle.oci.sdk - oci-java-sdk-keymanagement - - - com.oracle.oci.sdk - oci-java-sdk-secrets - - - com.oracle.oci.sdk - oci-java-sdk-vault - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciHandler.java b/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciHandler.java deleted file mode 100644 index 1eee9e8b5f2..00000000000 --- a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciHandler.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.examples.integrations.oci.vault.reactive; - -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.oracle.bmc.responses.AsyncHandler; - -final class OciHandler { - private static final Logger LOGGER = Logger.getLogger(OciHandler.class.getName()); - - private OciHandler() { - } - - static AsyncHandler ociHandler(Consumer handler) { - return new AsyncHandler<>() { - @Override - public void onSuccess(REQ req, RES res) { - handler.accept(res); - } - - @Override - public void onError(REQ req, Throwable error) { - LOGGER.log(Level.WARNING, "OCI Exception", error); - if (error instanceof Error) { - throw (Error) error; - } - if (error instanceof RuntimeException) { - throw (RuntimeException) error; - } - throw new RuntimeException(error); - } - }; - } -} diff --git a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciVaultMain.java b/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciVaultMain.java deleted file mode 100644 index d0c8cd586c4..00000000000 --- a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/OciVaultMain.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.vault.reactive; - -import java.io.IOException; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.keymanagement.KmsCryptoAsync; -import com.oracle.bmc.keymanagement.KmsCryptoAsyncClient; -import com.oracle.bmc.model.BmcException; -import com.oracle.bmc.secrets.SecretsAsync; -import com.oracle.bmc.secrets.SecretsAsyncClient; -import com.oracle.bmc.vault.VaultsAsync; -import com.oracle.bmc.vault.VaultsAsyncClient; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of the example. - * Boots a web server and provides REST API for Vault interactions. - */ -public final class OciVaultMain { - private OciVaultMain() { - } - - /** - * Main method. - * @param args ignored - */ - public static void main(String[] args) throws IOException { - LogConfig.configureRuntime(); - - // as I cannot share my configuration of OCI, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - Config vaultConfig = config.get("oci.vault"); - // the following three parameters are required - String vaultOcid = vaultConfig.get("vault-ocid").asString().get(); - String compartmentOcid = vaultConfig.get("compartment-ocid").asString().get(); - String encryptionKey = vaultConfig.get("encryption-key-ocid").asString().get(); - String signatureKey = vaultConfig.get("signature-key-ocid").asString().get(); - String cryptoEndpoint = vaultConfig.get("cryptographic-endpoint").asString().get(); - - // this requires OCI configuration in the usual place - // ~/.oci/config - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(ConfigFileReader.parseDefault()); - - SecretsAsync secrets = SecretsAsyncClient.builder().build(authProvider); - KmsCryptoAsync crypto = KmsCryptoAsyncClient.builder() - .endpoint(cryptoEndpoint) - .build(authProvider); - VaultsAsync vaults = VaultsAsyncClient.builder().build(authProvider); - - WebServer.builder() - .config(config.get("server")) - .routing(Routing.builder() - .register("/vault", new VaultService(secrets, - vaults, - crypto, - vaultOcid, - compartmentOcid, - encryptionKey, - signatureKey)) - // OCI SDK error handling - .error(BmcException.class, (req, res, ex) -> res.status(ex.getStatusCode()) - .send(ex.getMessage()))) - .build() - .start() - .await(); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/VaultService.java b/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/VaultService.java deleted file mode 100644 index 061ccb05819..00000000000 --- a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/VaultService.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.oci.vault.reactive; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Date; - -import io.helidon.common.Base64Value; -import io.helidon.webserver.Handler; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import com.oracle.bmc.keymanagement.KmsCryptoAsync; -import com.oracle.bmc.keymanagement.model.DecryptDataDetails; -import com.oracle.bmc.keymanagement.model.EncryptDataDetails; -import com.oracle.bmc.keymanagement.model.SignDataDetails; -import com.oracle.bmc.keymanagement.model.VerifyDataDetails; -import com.oracle.bmc.keymanagement.requests.DecryptRequest; -import com.oracle.bmc.keymanagement.requests.EncryptRequest; -import com.oracle.bmc.keymanagement.requests.SignRequest; -import com.oracle.bmc.keymanagement.requests.VerifyRequest; -import com.oracle.bmc.secrets.SecretsAsync; -import com.oracle.bmc.secrets.model.Base64SecretBundleContentDetails; -import com.oracle.bmc.secrets.model.SecretBundleContentDetails; -import com.oracle.bmc.secrets.requests.GetSecretBundleRequest; -import com.oracle.bmc.vault.VaultsAsync; -import com.oracle.bmc.vault.model.Base64SecretContentDetails; -import com.oracle.bmc.vault.model.CreateSecretDetails; -import com.oracle.bmc.vault.model.ScheduleSecretDeletionDetails; -import com.oracle.bmc.vault.model.SecretContentDetails; -import com.oracle.bmc.vault.requests.CreateSecretRequest; -import com.oracle.bmc.vault.requests.ScheduleSecretDeletionRequest; - -import static io.helidon.examples.integrations.oci.vault.reactive.OciHandler.ociHandler; - -class VaultService implements Service { - private final SecretsAsync secrets; - private final VaultsAsync vaults; - private final KmsCryptoAsync crypto; - private final String vaultOcid; - private final String compartmentOcid; - private final String encryptionKeyOcid; - private final String signatureKeyOcid; - - VaultService(SecretsAsync secrets, - VaultsAsync vaults, - KmsCryptoAsync crypto, - String vaultOcid, - String compartmentOcid, - String encryptionKeyOcid, - String signatureKeyOcid) { - this.secrets = secrets; - this.vaults = vaults; - this.crypto = crypto; - this.vaultOcid = vaultOcid; - this.compartmentOcid = compartmentOcid; - this.encryptionKeyOcid = encryptionKeyOcid; - this.signatureKeyOcid = signatureKeyOcid; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/encrypt/{text:.*}", this::encrypt) - .get("/decrypt/{text:.*}", this::decrypt) - .get("/sign/{text}", this::sign) - .post("/verify/{text}", Handler.create(String.class, this::verify)) - .get("/secret/{id}", this::getSecret) - .post("/secret/{name}", Handler.create(String.class, this::createSecret)) - .delete("/secret/{id}", this::deleteSecret); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - secrets.getSecretBundle(GetSecretBundleRequest.builder() - .secretId(req.path().param("id")) - .build(), ociHandler(ociRes -> { - SecretBundleContentDetails content = ociRes.getSecretBundle().getSecretBundleContent(); - if (content instanceof Base64SecretBundleContentDetails) { - // the only supported type - res.send(Base64Value.createFromEncoded(((Base64SecretBundleContentDetails) content).getContent()) - .toDecodedString()); - } else { - req.next(new Exception("Invalid secret content type")); - } - })); - } - - private void deleteSecret(ServerRequest req, ServerResponse res) { - // has to be for quite a long period of time - did not work with less than 30 days - Date deleteTime = Date.from(Instant.now().plus(30, ChronoUnit.DAYS)); - - String secretOcid = req.path().param("id"); - - vaults.scheduleSecretDeletion(ScheduleSecretDeletionRequest.builder() - .secretId(secretOcid) - .scheduleSecretDeletionDetails(ScheduleSecretDeletionDetails.builder() - .timeOfDeletion(deleteTime) - .build()) - .build(), ociHandler(ociRes -> res.send("Secret " + secretOcid - + " was marked for deletion"))); - } - - private void createSecret(ServerRequest req, ServerResponse res, String secretText) { - SecretContentDetails content = Base64SecretContentDetails.builder() - .content(Base64Value.create(secretText).toBase64()) - .build(); - - vaults.createSecret(CreateSecretRequest.builder() - .createSecretDetails(CreateSecretDetails.builder() - .secretName(req.path().param("name")) - .vaultId(vaultOcid) - .compartmentId(compartmentOcid) - .keyId(encryptionKeyOcid) - .secretContent(content) - .build()) - .build(), ociHandler(ociRes -> res.send(ociRes.getSecret().getId()))); - } - - private void verify(ServerRequest req, ServerResponse res, String signature) { - String text = req.path().param("text"); - VerifyDataDetails.SigningAlgorithm algorithm = VerifyDataDetails.SigningAlgorithm.Sha224RsaPkcsPss; - - crypto.verify(VerifyRequest.builder() - .verifyDataDetails(VerifyDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(algorithm) - .message(Base64Value.create(text).toBase64()) - .signature(signature) - .build()) - .build(), - ociHandler(ociRes -> { - boolean valid = ociRes.getVerifiedData() - .getIsSignatureValid(); - res.send(valid ? "Signature valid" : "Signature not valid"); - })); - } - - private void sign(ServerRequest req, ServerResponse res) { - crypto.sign(SignRequest.builder() - .signDataDetails(SignDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(SignDataDetails.SigningAlgorithm.Sha224RsaPkcsPss) - .message(Base64Value.create(req.path().param("text")).toBase64()) - .build()) - .build(), ociHandler(ociRes -> res.send(ociRes.getSignedData() - .getSignature()))); - } - - private void encrypt(ServerRequest req, ServerResponse res) { - crypto.encrypt(EncryptRequest.builder() - .encryptDataDetails(EncryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .plaintext(Base64Value.create(req.path().param("text")).toBase64()) - .build()) - .build(), ociHandler(ociRes -> res.send(ociRes.getEncryptedData().getCiphertext()))); - } - - private void decrypt(ServerRequest req, ServerResponse res) { - crypto.decrypt(DecryptRequest.builder() - .decryptDataDetails(DecryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .ciphertext(req.path().param("text")) - .build()) - .build(), ociHandler(ociRes -> res.send(Base64Value.createFromEncoded(ociRes.getDecryptedData() - .getPlaintext()) - .toDecodedString()))); - } -} diff --git a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/package-info.java b/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/package-info.java deleted file mode 100644 index 23e07e67fd2..00000000000 --- a/examples/integrations/oci/vault-reactive/src/main/java/io/helidon/examples/integrations/oci/vault/reactive/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of OCI Vault integration in a reactive application. - */ -package io.helidon.examples.integrations.oci.vault.reactive; diff --git a/examples/integrations/oci/vault-reactive/src/main/resources/application.yaml b/examples/integrations/oci/vault-reactive/src/main/resources/application.yaml deleted file mode 100644 index 982ef550c45..00000000000 --- a/examples/integrations/oci/vault-reactive/src/main/resources/application.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 8080 - -# -# The following properties under oci are accessed by Helidon. Values -# under oci.properties.* are read from ~/helidon/conf/examples.yaml. -# -oci: - vault: - # Vault OCID (the vault you want to use for this example - vault-ocid: "${oci.properties.vault-ocid}" - compartment-ocid: "${oci.properties.compartment-ocid}" - encryption-key-ocid: "${oci.properties.vault-key-ocid}" - signature-key-ocid: "${oci.properties.vault-rsa-key-ocid}" - cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" diff --git a/examples/integrations/oci/vault-reactive/src/main/resources/logging.properties b/examples/integrations/oci/vault-reactive/src/main/resources/logging.properties deleted file mode 100644 index d0317654f47..00000000000 --- a/examples/integrations/oci/vault-reactive/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/pom.xml b/examples/integrations/pom.xml deleted file mode 100644 index 104b802504d..00000000000 --- a/examples/integrations/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.integrations - helidon-examples-integrations-project - Helidon Integrations Examples - pom - - - cdi - micronaut - neo4j - micrometer - oci - vault - microstream - - - diff --git a/examples/integrations/vault/hcp-cdi/README.md b/examples/integrations/vault/hcp-cdi/README.md deleted file mode 100644 index 3e2aa9c8b90..00000000000 --- a/examples/integrations/vault/hcp-cdi/README.md +++ /dev/null @@ -1,26 +0,0 @@ -HCP Vault Integration with Reactive APIs ---- - -This example expects an empty Vault. It uses the token to create all required resources. - -To run this example: - -1. Run a docker image with a known root token - -```shell -docker run --cap-add=IPC_LOCK -e VAULT_DEV_ROOT_TOKEN_ID=myroot -d --name=vault -p8200:8200 vault -``` - -2. Build this application - -```shell -mvn clean package -``` - -3. Start this application - -```shell -java -jar ./target/ -``` - -4. Exercise the endpoints \ No newline at end of file diff --git a/examples/integrations/vault/hcp-cdi/pom.xml b/examples/integrations/vault/hcp-cdi/pom.xml deleted file mode 100644 index 49a92f00015..00000000000 --- a/examples/integrations/vault/hcp-cdi/pom.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.vault - helidon-examples-integrations-vault-hcp-cdi - Helidon Examples Integration Vault CDI - CDI integration with Vault. - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.vault - helidon-integrations-vault-cdi - - - io.helidon.config - helidon-config-yaml - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-token - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-approle - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv1 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv2 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-cubbyhole - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-transit - - - io.helidon.integrations.vault.sys - helidon-integrations-vault-sys - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/CubbyholeResource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/CubbyholeResource.java deleted file mode 100644 index b205bc81b50..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/CubbyholeResource.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.cdi; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.integrations.vault.Secret; -import io.helidon.integrations.vault.secrets.cubbyhole.CreateCubbyhole; -import io.helidon.integrations.vault.secrets.cubbyhole.CubbyholeSecrets; -import io.helidon.integrations.vault.secrets.cubbyhole.DeleteCubbyhole; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Cubbyhole secrets engine operations. - */ -@Path("/cubbyhole") -public class CubbyholeResource { - private final CubbyholeSecrets secrets; - - @Inject - CubbyholeResource(CubbyholeSecrets secrets) { - this.secrets = secrets; - } - - /** - * Create a secret from request entity, the name of the value is {@code secret}. - * - * @param path path of the secret taken from request path - * @param secret secret from the entity - * @return response - */ - @POST - @Path("/secrets/{path: .*}") - public Response createSecret(@PathParam("path") String path, String secret) { - CreateCubbyhole.Response response = secrets.create(path, Map.of("secret", secret)); - - return Response.ok() - .entity("Created secret on path: " + path + ", key is \"secret\", original status: " + response.status().code()) - .build(); - } - - /** - * Delete the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @DELETE - @Path("/secrets/{path: .*}") - public Response deleteSecret(@PathParam("path") String path) { - DeleteCubbyhole.Response response = secrets.delete(path); - - return Response.ok() - .entity("Deleted secret on path: " + path + ". Original status: " + response.status().code()) - .build(); - } - - /** - * Get the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @GET - @Path("/secrets/{path: .*}") - public Response getSecret(@PathParam("path") String path) { - Optional secret = secrets.get(path); - - if (secret.isPresent()) { - Secret kv1Secret = secret.get(); - return Response.ok() - .entity("Secret: " + secret.get().values().toString()) - .build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv1Resource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv1Resource.java deleted file mode 100644 index 85db40b49e3..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv1Resource.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.integrations.vault.Secret; -import io.helidon.integrations.vault.secrets.kv1.CreateKv1; -import io.helidon.integrations.vault.secrets.kv1.DeleteKv1; -import io.helidon.integrations.vault.secrets.kv1.Kv1Secrets; -import io.helidon.integrations.vault.secrets.kv1.Kv1SecretsRx; -import io.helidon.integrations.vault.sys.DisableEngine; -import io.helidon.integrations.vault.sys.EnableEngine; -import io.helidon.integrations.vault.sys.Sys; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Key/Value version 1 secrets engine operations. - */ -@Path("/kv1") -public class Kv1Resource { - private final Sys sys; - private final Kv1Secrets secrets; - - @Inject - Kv1Resource(Sys sys, Kv1Secrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - /** - * Enable the secrets engine on the default path. - * - * @return response - */ - @Path("/engine") - @GET - public Response enableEngine() { - EnableEngine.Response response = sys.enableEngine(Kv1SecretsRx.ENGINE); - - return Response.ok() - .entity("Key/value version 1 secret engine is now enabled. Original status: " + response.status().code()) - .build(); - } - - /** - * Disable the secrets engine on the default path. - * @return response - */ - @Path("/engine") - @DELETE - public Response disableEngine() { - DisableEngine.Response response = sys.disableEngine(Kv1SecretsRx.ENGINE); - return Response.ok() - .entity("Key/value version 1 secret engine is now disabled. Original status: " + response.status().code()) - .build(); - } - - /** - * Create a secret from request entity, the name of the value is {@code secret}. - * - * @param path path of the secret taken from request path - * @param secret secret from the entity - * @return response - */ - @POST - @Path("/secrets/{path: .*}") - public Response createSecret(@PathParam("path") String path, String secret) { - CreateKv1.Response response = secrets.create(path, Map.of("secret", secret)); - - return Response.ok() - .entity("Created secret on path: " + path + ", key is \"secret\", original status: " + response.status().code()) - .build(); - } - - /** - * Delete the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @DELETE - @Path("/secrets/{path: .*}") - public Response deleteSecret(@PathParam("path") String path) { - DeleteKv1.Response response = secrets.delete(path); - - return Response.ok() - .entity("Deleted secret on path: " + path + ". Original status: " + response.status().code()) - .build(); - } - - /** - * Get the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @GET - @Path("/secrets/{path: .*}") - public Response getSecret(@PathParam("path") String path) { - Optional secret = secrets.get(path); - - if (secret.isPresent()) { - Secret kv1Secret = secret.get(); - return Response.ok() - .entity("Secret: " + secret.get().values().toString()) - .build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv2Resource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv2Resource.java deleted file mode 100644 index 05ef0b81cd5..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv2Resource.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.cdi; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.integrations.vault.secrets.kv2.CreateKv2; -import io.helidon.integrations.vault.secrets.kv2.DeleteAllKv2; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secrets; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Key/Value version 2 secrets engine operations. - */ -@Path("/kv2") -public class Kv2Resource { - private final Kv2Secrets secrets; - - @Inject - Kv2Resource(Kv2Secrets secrets) { - this.secrets = secrets; - } - - /** - * Create a secret from request entity, the name of the value is {@code secret}. - * - * @param path path of the secret taken from request path - * @param secret secret from the entity - * @return response - */ - @POST - @Path("/secrets/{path: .*}") - public Response createSecret(@PathParam("path") String path, String secret) { - CreateKv2.Response response = secrets.create(path, Map.of("secret", secret)); - - return Response.ok() - .entity("Created secret on path: " + path + ", key is \"secret\", original status: " + response.status().code()) - .build(); - } - - /** - * Delete the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @DELETE - @Path("/secrets/{path: .*}") - public Response deleteSecret(@PathParam("path") String path) { - DeleteAllKv2.Response response = secrets.deleteAll(path); - - return Response.ok() - .entity("Deleted secret on path: " + path + ". Original status: " + response.status().code()) - .build(); - } - - /** - * Get the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @GET - @Path("/secrets/{path: .*}") - public Response getSecret(@PathParam("path") String path) { - - Optional secret = secrets.get(path); - - if (secret.isPresent()) { - Kv2Secret kv2Secret = secret.get(); - return Response.ok() - .entity("Version " + kv2Secret.metadata().version() + ", secret: " + kv2Secret.values().toString()) - .build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/TransitResource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/TransitResource.java deleted file mode 100644 index 595e9dc0e83..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/TransitResource.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.cdi; - -import io.helidon.common.Base64Value; -import io.helidon.integrations.vault.secrets.transit.CreateKey; -import io.helidon.integrations.vault.secrets.transit.Decrypt; -import io.helidon.integrations.vault.secrets.transit.DeleteKey; -import io.helidon.integrations.vault.secrets.transit.Encrypt; -import io.helidon.integrations.vault.secrets.transit.Hmac; -import io.helidon.integrations.vault.secrets.transit.Sign; -import io.helidon.integrations.vault.secrets.transit.TransitSecrets; -import io.helidon.integrations.vault.secrets.transit.TransitSecretsRx; -import io.helidon.integrations.vault.secrets.transit.UpdateKeyConfig; -import io.helidon.integrations.vault.secrets.transit.Verify; -import io.helidon.integrations.vault.sys.DisableEngine; -import io.helidon.integrations.vault.sys.EnableEngine; -import io.helidon.integrations.vault.sys.Sys; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Transit secrets engine operations. - */ -@Path("/transit") -public class TransitResource { - private static final String ENCRYPTION_KEY = "encryption-key"; - private static final String SIGNATURE_KEY = "signature-key"; - - private final Sys sys; - private final TransitSecrets secrets; - - @Inject - TransitResource(Sys sys, TransitSecrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - /** - * Enable the secrets engine on the default path. - * - * @return response - */ - @Path("/engine") - @GET - public Response enableEngine() { - EnableEngine.Response response = sys.enableEngine(TransitSecretsRx.ENGINE); - - return Response.ok() - .entity("Transit secret engine is now enabled. Original status: " + response.status().code()) - .build(); - } - - /** - * Disable the secrets engine on the default path. - * @return response - */ - @Path("/engine") - @DELETE - public Response disableEngine() { - DisableEngine.Response response = sys.disableEngine(TransitSecretsRx.ENGINE); - - return Response.ok() - .entity("Transit secret engine is now disabled. Original status: " + response.status()) - .build(); - } - - /** - * Create the encrypting and signature keys. - * - * @return response - */ - @Path("/keys") - @GET - public Response createKeys() { - secrets.createKey(CreateKey.Request.builder() - .name(ENCRYPTION_KEY)); - - secrets.createKey(CreateKey.Request.builder() - .name(SIGNATURE_KEY) - .type("rsa-2048")); - - return Response.ok() - .entity("Created encryption (and HMAC), and signature keys") - .build(); - } - - /** - * Delete the encryption and signature keys. - * - * @return response - */ - @Path("/keys") - @DELETE - public Response deleteKeys() { - // we must first enable deletion of the key (by default it cannot be deleted) - secrets.updateKeyConfig(UpdateKeyConfig.Request.builder() - .name(ENCRYPTION_KEY) - .allowDeletion(true)); - - secrets.updateKeyConfig(UpdateKeyConfig.Request.builder() - .name(SIGNATURE_KEY) - .allowDeletion(true)); - - secrets.deleteKey(DeleteKey.Request.create(ENCRYPTION_KEY)); - secrets.deleteKey(DeleteKey.Request.create(SIGNATURE_KEY)); - - return Response.ok() - .entity("Deleted encryption (and HMAC), and signature keys") - .build(); - } - - /** - * Encrypt a secret. - * - * @param secret provided as part of the path - * @return cipher text - */ - @Path("/encrypt/{secret: .*}") - @GET - public String encryptSecret(@PathParam("secret") String secret) { - return secrets.encrypt(Encrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(secret))) - .encrypted() - .cipherText(); - } - - /** - * Decrypt a secret. - * - * @param cipherText provided as part of the path - * @return decrypted secret text - */ - @Path("/decrypt/{cipherText: .*}") - @GET - public String decryptSecret(@PathParam("cipherText") String cipherText) { - return secrets.decrypt(Decrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .cipherText(cipherText)) - .decrypted() - .toDecodedString(); - } - - /** - * Create an HMAC for text. - * - * @param text text to do HMAC for - * @return hmac string that can be used to {@link #verifyHmac(String, String)} - */ - @Path("/hmac/{text}") - @GET - public String hmac(@PathParam("text") String text) { - return secrets.hmac(Hmac.Request.builder() - .hmacKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(text))) - .hmac(); - } - - /** - * Create a signature for text. - * - * @param text text to sign - * @return signature string that can be used to {@link #verifySignature(String, String)} - */ - @Path("/sign/{text}") - @GET - public String sign(@PathParam("text") String text) { - return secrets.sign(Sign.Request.builder() - .signatureKeyName(SIGNATURE_KEY) - .data(Base64Value.create(text))) - .signature(); - } - - /** - * Verify HMAC. - * - * @param secret secret that was used to {@link #hmac(String)} - * @param hmac HMAC text - * @return {@code HMAC Valid} or {@code HMAC Invalid} - */ - @Path("/verify/hmac/{secret}/{hmac: .*}") - @GET - public String verifyHmac(@PathParam("secret") String secret, @PathParam("hmac") String hmac) { - boolean isValid = secrets.verify(Verify.Request.builder() - .digestKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(secret)) - .hmac(hmac)) - .isValid(); - - return (isValid ? "HMAC Valid" : "HMAC Invalid"); - } - - /** - * Verify signature. - * - * @param secret secret that was used to {@link #sign(String)} - * @param signature signature - * @return {@code Signature Valid} or {@code Signature Invalid} - */ - @Path("/verify/sign/{secret}/{signature: .*}") - @GET - public String verifySignature(@PathParam("secret") String secret, @PathParam("signature") String signature) { - boolean isValid = secrets.verify(Verify.Request.builder() - .digestKeyName(SIGNATURE_KEY) - .data(Base64Value.create(secret)) - .signature(signature)) - .isValid(); - - return (isValid ? "Signature Valid" : "Signature Invalid"); - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/VaultCdiMain.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/VaultCdiMain.java deleted file mode 100644 index 82fd04ca2f0..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/VaultCdiMain.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.cdi; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.microprofile.cdi.Main; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.eclipse.microprofile.config.spi.ConfigSource; - -/** - * Main class of example. - */ -public final class VaultCdiMain { - private VaultCdiMain() { - } - - /** - * Main method of example. - * - * @param args ignored - */ - public static void main(String[] args) { - ConfigProviderResolver configProvider = ConfigProviderResolver.instance(); - - Config mpConfig = configProvider.getBuilder() - .addDefaultSources() - .withSources(examplesConfig()) - .addDiscoveredSources() - .addDiscoveredConverters() - .build(); - - // configure - configProvider.registerConfig(mpConfig, null); - - // start CDI - Main.main(args); - } - - private static ConfigSource[] examplesConfig() { - Path path = Paths.get(System.getProperty("user.home") + "/helidon/conf/examples.yaml"); - if (Files.exists(path)) { - return new ConfigSource[] {YamlMpConfigSource.create(path)}; - } - return new ConfigSource[0]; - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/package-info.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/package-info.java deleted file mode 100644 index 05acc2464ff..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of Helidon integration with Hashicorp Vault within CDI. - */ -package io.helidon.examples.integrations.vault.hcp.cdi; diff --git a/examples/integrations/vault/hcp-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/vault/hcp-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/vault/hcp-cdi/src/main/resources/application.yaml b/examples/integrations/vault/hcp-cdi/src/main/resources/application.yaml deleted file mode 100644 index d028f2cbca7..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server.port: 8080 - -vault: - default: - address: "http://localhost:8200" - token: "myroot" - auth: - app-role: - enabled: false - token: - enabled: true diff --git a/examples/integrations/vault/hcp-cdi/src/main/resources/logging.properties b/examples/integrations/vault/hcp-cdi/src/main/resources/logging.properties deleted file mode 100644 index d0317654f47..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/vault/hcp-reactive/README.md b/examples/integrations/vault/hcp-reactive/README.md deleted file mode 100644 index 3e2aa9c8b90..00000000000 --- a/examples/integrations/vault/hcp-reactive/README.md +++ /dev/null @@ -1,26 +0,0 @@ -HCP Vault Integration with Reactive APIs ---- - -This example expects an empty Vault. It uses the token to create all required resources. - -To run this example: - -1. Run a docker image with a known root token - -```shell -docker run --cap-add=IPC_LOCK -e VAULT_DEV_ROOT_TOKEN_ID=myroot -d --name=vault -p8200:8200 vault -``` - -2. Build this application - -```shell -mvn clean package -``` - -3. Start this application - -```shell -java -jar ./target/ -``` - -4. Exercise the endpoints \ No newline at end of file diff --git a/examples/integrations/vault/hcp-reactive/pom.xml b/examples/integrations/vault/hcp-reactive/pom.xml deleted file mode 100644 index d4c4081370c..00000000000 --- a/examples/integrations/vault/hcp-reactive/pom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.vault - helidon-examples-integrations-vault-hcp-reactive - Helidon Examples Integration Vault Reactive - Reactive integration with Vault. - - - io.helidon.examples.integrations.vault.hcp.reactive.ReactiveVaultMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.integrations.vault - helidon-integrations-vault - - - io.helidon.config - helidon-config-yaml - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-token - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-approle - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-k8s - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv1 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv2 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-cubbyhole - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-transit - - - io.helidon.integrations.vault.sys - helidon-integrations-vault-sys - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/AppRoleExample.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/AppRoleExample.java deleted file mode 100644 index 9679c6e214c..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/AppRoleExample.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.time.Duration; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.integrations.common.rest.ApiResponse; -import io.helidon.integrations.vault.Vault; -import io.helidon.integrations.vault.auths.approle.AppRoleAuthRx; -import io.helidon.integrations.vault.auths.approle.AppRoleVaultAuth; -import io.helidon.integrations.vault.auths.approle.CreateAppRole; -import io.helidon.integrations.vault.auths.approle.GenerateSecretId; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2SecretsRx; -import io.helidon.integrations.vault.sys.EnableAuth; -import io.helidon.integrations.vault.sys.SysRx; - -class AppRoleExample { - private static final String SECRET_PATH = "approle/example/secret"; - private static final String ROLE_NAME = "approle_role"; - private static final String POLICY_NAME = "approle_policy"; - private static final String CUSTOM_APP_ROLE_PATH = "customapprole"; - - private final Vault tokenVault; - private final Config config; - private final SysRx sys; - - private Vault appRoleVault; - - AppRoleExample(Vault tokenVault, Config config) { - this.tokenVault = tokenVault; - this.config = config; - - this.sys = tokenVault.sys(SysRx.API); - } - - public Single run() { - /* - The following tasks must be run before we authenticate - */ - return enableAppRoleAuth() - // Now we can login using AppRole - .flatMapSingle(ignored -> workWithSecrets()) - // Now back to token based Vault, as we will clean up - .flatMapSingle(ignored -> disableAppRoleAuth()) - .map(ignored -> "AppRole example finished successfully."); - } - - private Single workWithSecrets() { - Kv2SecretsRx secrets = appRoleVault.secrets(Kv2SecretsRx.ENGINE); - - return secrets.create(SECRET_PATH, Map.of("secret-key", "secretValue", - "secret-user", "username")) - .flatMapSingle(ignored -> secrets.get(SECRET_PATH)) - .peek(secret -> { - if (secret.isPresent()) { - Kv2Secret kv2Secret = secret.get(); - System.out.println("appRole first secret: " + kv2Secret.value("secret-key")); - System.out.println("appRole second secret: " + kv2Secret.value("secret-user")); - } else { - System.out.println("appRole secret not found"); - } - }).flatMapSingle(ignored -> secrets.deleteAll(SECRET_PATH)); - } - - private Single disableAppRoleAuth() { - return sys.deletePolicy(POLICY_NAME) - .flatMapSingle(ignored -> sys.disableAuth(CUSTOM_APP_ROLE_PATH)); - } - - private Single enableAppRoleAuth() { - AtomicReference roleId = new AtomicReference<>(); - AtomicReference secretId = new AtomicReference<>(); - - // enable the method - return sys.enableAuth(EnableAuth.Request.builder() - .auth(AppRoleAuthRx.AUTH_METHOD) - // must be aligned with path configured in application.yaml - .path(CUSTOM_APP_ROLE_PATH)) - // add policy - .flatMapSingle(ignored -> sys.createPolicy(POLICY_NAME, VaultPolicy.POLICY)) - .flatMapSingle(ignored -> tokenVault.auth(AppRoleAuthRx.AUTH_METHOD, CUSTOM_APP_ROLE_PATH) - .createAppRole(CreateAppRole.Request.builder() - .roleName(ROLE_NAME) - .addTokenPolicy(POLICY_NAME) - .tokenExplicitMaxTtl(Duration.ofMinutes(1)))) - .flatMapSingle(ignored -> tokenVault.auth(AppRoleAuthRx.AUTH_METHOD, CUSTOM_APP_ROLE_PATH) - .readRoleId(ROLE_NAME)) - .peek(it -> it.ifPresent(roleId::set)) - .flatMapSingle(ignored -> tokenVault.auth(AppRoleAuthRx.AUTH_METHOD, CUSTOM_APP_ROLE_PATH) - .generateSecretId(GenerateSecretId.Request.builder() - .roleName(ROLE_NAME) - .addMetadata("name", "helidon"))) - .map(GenerateSecretId.Response::secretId) - .peek(secretId::set) - .peek(ignored -> { - System.out.println("roleId: " + roleId.get()); - System.out.println("secretId: " + secretId.get()); - appRoleVault = Vault.builder() - .config(config) - .addVaultAuth(AppRoleVaultAuth.builder() - .path(CUSTOM_APP_ROLE_PATH) - .appRoleId(roleId.get()) - .secretId(secretId.get()) - .build()) - .build(); - }); - } -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/CubbyholeService.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/CubbyholeService.java deleted file mode 100644 index de4b3164fef..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/CubbyholeService.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.util.Map; - -import io.helidon.common.http.Http; -import io.helidon.integrations.vault.secrets.cubbyhole.CubbyholeSecretsRx; -import io.helidon.integrations.vault.sys.SysRx; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -class CubbyholeService implements Service { - private final SysRx sys; - private final CubbyholeSecretsRx secrets; - - CubbyholeService(SysRx sys, CubbyholeSecretsRx secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/create", this::createSecrets) - .get("/secrets/{path:.*}", this::getSecret); - } - - private void createSecrets(ServerRequest req, ServerResponse res) { - secrets.create("first/secret", Map.of("key", "secretValue")) - .thenAccept(ignored -> res.send("Created secret on path /first/secret")) - .exceptionally(res::send); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - String path = req.path().param("path"); - - secrets.get(path) - .thenAccept(secret -> { - if (secret.isPresent()) { - // using toString so we do not need to depend on JSON-B - res.send(secret.get().values().toString()); - } else { - res.status(Http.Status.NOT_FOUND_404); - res.send(); - } - }) - .exceptionally(res::send); - } -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/K8sExample.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/K8sExample.java deleted file mode 100644 index e934b8160b4..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/K8sExample.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.util.Map; -import java.util.function.Function; - -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.integrations.common.rest.ApiResponse; -import io.helidon.integrations.vault.Vault; -import io.helidon.integrations.vault.auths.k8s.ConfigureK8s; -import io.helidon.integrations.vault.auths.k8s.CreateRole; -import io.helidon.integrations.vault.auths.k8s.K8sAuthRx; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2SecretsRx; -import io.helidon.integrations.vault.sys.SysRx; - -class K8sExample { - private static final String SECRET_PATH = "k8s/example/secret"; - private static final String POLICY_NAME = "k8s_policy"; - - private final Vault tokenVault; - private final String k8sAddress; - private final Config config; - private final SysRx sys; - - private Vault k8sVault; - - K8sExample(Vault tokenVault, Config config) { - this.tokenVault = tokenVault; - this.sys = tokenVault.sys(SysRx.API); - this.k8sAddress = config.get("cluster-address").asString().get(); - this.config = config; - } - - public Single run() { - /* - The following tasks must be run before we authenticate - */ - return enableK8sAuth() - // Now we can login using k8s - must run within a k8s cluster (or you need the k8s configuration files locally) - .flatMapSingle(ignored -> workWithSecrets()) - // Now back to token based Vault, as we will clean up - .flatMapSingle(ignored -> disableK8sAuth()) - .map(ignored -> "k8s example finished successfully."); - } - - private Single workWithSecrets() { - Kv2SecretsRx secrets = k8sVault.secrets(Kv2SecretsRx.ENGINE); - - return secrets.create(SECRET_PATH, Map.of("secret-key", "secretValue", - "secret-user", "username")) - .flatMapSingle(ignored -> secrets.get(SECRET_PATH)) - .peek(secret -> { - if (secret.isPresent()) { - Kv2Secret kv2Secret = secret.get(); - System.out.println("k8s first secret: " + kv2Secret.value("secret-key")); - System.out.println("k8s second secret: " + kv2Secret.value("secret-user")); - } else { - System.out.println("k8s secret not found"); - } - }).flatMapSingle(ignored -> secrets.deleteAll(SECRET_PATH)); - } - - private Single disableK8sAuth() { - return sys.deletePolicy(POLICY_NAME) - .flatMapSingle(ignored -> sys.disableAuth(K8sAuthRx.AUTH_METHOD.defaultPath())); - } - - private Single enableK8sAuth() { - // enable the method - return sys.enableAuth(K8sAuthRx.AUTH_METHOD) - // add policy - .flatMapSingle(ignored -> sys.createPolicy(POLICY_NAME, VaultPolicy.POLICY)) - .flatMapSingle(ignored -> tokenVault.auth(K8sAuthRx.AUTH_METHOD) - .configure(ConfigureK8s.Request.builder() - .address(k8sAddress))) - .flatMapSingle(ignored -> tokenVault.auth(K8sAuthRx.AUTH_METHOD) - // this must be the same role name as is defined in application.yaml - .createRole(CreateRole.Request.builder() - .roleName("my-role") - .addBoundServiceAccountName("*") - .addBoundServiceAccountNamespace("default") - .addTokenPolicy(POLICY_NAME))) - .peek(ignored -> k8sVault = Vault.create(config)) - .map(Function.identity()); - } -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv1Service.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv1Service.java deleted file mode 100644 index af51c5db8ba..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv1Service.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.util.Map; - -import io.helidon.common.http.Http; -import io.helidon.integrations.vault.secrets.kv1.Kv1SecretsRx; -import io.helidon.integrations.vault.sys.SysRx; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -class Kv1Service implements Service { - private final SysRx sys; - private final Kv1SecretsRx secrets; - - Kv1Service(SysRx sys, Kv1SecretsRx secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/enable", this::enableEngine) - .get("/create", this::createSecrets) - .get("/secrets/{path:.*}", this::getSecret) - .delete("/secrets/{path:.*}", this::deleteSecret) - .get("/disable", this::disableEngine); - } - - private void disableEngine(ServerRequest req, ServerResponse res) { - sys.disableEngine(Kv1SecretsRx.ENGINE) - .thenAccept(ignored -> res.send("KV1 Secret engine disabled")) - .exceptionally(res::send); - } - - private void enableEngine(ServerRequest req, ServerResponse res) { - sys.enableEngine(Kv1SecretsRx.ENGINE) - .thenAccept(ignored -> res.send("KV1 Secret engine enabled")) - .exceptionally(res::send); - } - - private void createSecrets(ServerRequest req, ServerResponse res) { - secrets.create("first/secret", Map.of("key", "secretValue")) - .thenAccept(ignored -> res.send("Created secret on path /first/secret")) - .exceptionally(res::send); - } - - private void deleteSecret(ServerRequest req, ServerResponse res) { - String path = req.path().param("path"); - - secrets.delete(path) - .thenAccept(ignored -> res.send("Deleted secret on path " + path)); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - String path = req.path().param("path"); - - secrets.get(path) - .thenAccept(secret -> { - if (secret.isPresent()) { - // using toString so we do not need to depend on JSON-B - res.send(secret.get().values().toString()); - } else { - res.status(Http.Status.NOT_FOUND_404); - res.send(); - } - }) - .exceptionally(res::send); - } -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv2Service.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv2Service.java deleted file mode 100644 index 3b74d576c2f..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/Kv2Service.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.util.Map; - -import io.helidon.common.http.Http; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2SecretsRx; -import io.helidon.integrations.vault.sys.SysRx; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -class Kv2Service implements Service { - private final SysRx sys; - private final Kv2SecretsRx secrets; - - Kv2Service(SysRx sys, Kv2SecretsRx secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/create", this::createSecrets) - .get("/secrets/{path:.*}", this::getSecret) - .delete("/secrets/{path:.*}", this::deleteSecret); - } - - private void createSecrets(ServerRequest req, ServerResponse res) { - secrets.create("first/secret", Map.of("key", "secretValue")) - .thenAccept(ignored -> res.send("Created secret on path /first/secret")) - .exceptionally(res::send); - } - - private void deleteSecret(ServerRequest req, ServerResponse res) { - String path = req.path().param("path"); - - secrets.deleteAll(path) - .thenAccept(ignored -> res.send("Deleted secret on path " + path)); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - String path = req.path().param("path"); - - secrets.get(path) - .thenAccept(secret -> { - if (secret.isPresent()) { - // using toString so we do not need to depend on JSON-B - Kv2Secret kv2Secret = secret.get(); - res.send("Version " + kv2Secret.metadata().version() + ", secret: " + kv2Secret.values().toString()); - } else { - res.status(Http.Status.NOT_FOUND_404); - res.send(); - } - }) - .exceptionally(res::send); - } -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/ReactiveVaultMain.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/ReactiveVaultMain.java deleted file mode 100644 index d85ac848b35..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/ReactiveVaultMain.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.util.concurrent.TimeUnit; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.CompletionAwaitable; -import io.helidon.config.Config; -import io.helidon.integrations.vault.Vault; -import io.helidon.integrations.vault.secrets.cubbyhole.CubbyholeSecretsRx; -import io.helidon.integrations.vault.secrets.kv1.Kv1SecretsRx; -import io.helidon.integrations.vault.secrets.kv2.Kv2SecretsRx; -import io.helidon.integrations.vault.secrets.transit.TransitSecretsRx; -import io.helidon.integrations.vault.sys.SysRx; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of example. - */ -public final class ReactiveVaultMain { - private ReactiveVaultMain() { - } - - /** - * Main method of example. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - // as I cannot share my secret configuration, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - // we have three configurations available - // 1. Token based authentication - Vault tokenVault = Vault.builder() - .config(config.get("vault.token")) - .updateWebClient(it -> it.connectTimeout(5, TimeUnit.SECONDS) - .readTimeout(5, TimeUnit.SECONDS)) - .build(); - - // 2. App role based authentication - must be created after we obtain the role id an token - // 3. Kubernetes (k8s) based authentication (requires to run on k8s) - must be created after we create - // the authentication method - - // the tokenVault is using the root token and can be used to enable engines and - // other authentication mechanisms - - CompletionAwaitable k8sFuture = new K8sExample(tokenVault, config.get("vault.k8s")) - .run() - .forSingle(System.out::println); - - CompletionAwaitable appRoleFuture = new AppRoleExample(tokenVault, config.get("vault.approle")) - .run() - .forSingle(System.out::println); - - /* - We do not need to block here for our examples, as the server started below will keep the process running - */ - - SysRx sys = tokenVault.sys(SysRx.API); - // we use await for webserver, as we do not care if we block the main thread - it is not used - // for anything - WebServer webServer = WebServer.builder() - .config(config.get("server")) - .routing(Routing.builder() - .register("/cubbyhole", new CubbyholeService(sys, tokenVault.secrets(CubbyholeSecretsRx.ENGINE))) - .register("/kv1", new Kv1Service(sys, tokenVault.secrets(Kv1SecretsRx.ENGINE))) - .register("/kv2", new Kv2Service(sys, tokenVault.secrets(Kv2SecretsRx.ENGINE))) - .register("/transit", new TransitService(sys, tokenVault.secrets(TransitSecretsRx.ENGINE)))) - .build() - .start() - .await(); - - try { - appRoleFuture.await(); - } catch (Exception e) { - System.err.println("AppRole example failed"); - e.printStackTrace(); - } - - try { - k8sFuture.await(); - } catch (Exception e) { - System.err.println("Kubernetes example failed"); - e.printStackTrace(); - } - - String baseAddress = "http://localhost:" + webServer.port() + "/"; - System.out.println("Server started on " + baseAddress); - System.out.println(); - System.out.println("Key/Value Version 1 Secrets Engine"); - System.out.println("\t" + baseAddress + "kv1/enable"); - System.out.println("\t" + baseAddress + "kv1/create"); - System.out.println("\t" + baseAddress + "kv1/secrets/first/secret"); - System.out.println("\tcurl -i -X DELETE " + baseAddress + "kv1/secrets/first/secret"); - System.out.println("\t" + baseAddress + "kv1/disable"); - System.out.println(); - System.out.println("Key/Value Version 2 Secrets Engine"); - System.out.println("\t" + baseAddress + "kv2/create"); - System.out.println("\t" + baseAddress + "kv2/secrets/first/secret"); - System.out.println("\tcurl -i -X DELETE " + baseAddress + "kv2/secrets/first/secret"); - System.out.println(); - System.out.println("Transit Secrets Engine"); - System.out.println("\t" + baseAddress + "transit/enable"); - System.out.println("\t" + baseAddress + "transit/keys"); - System.out.println("\t" + baseAddress + "transit/encrypt/secret_text"); - System.out.println("\t" + baseAddress + "transit/decrypt/cipher_text"); - System.out.println("\t" + baseAddress + "transit/sign"); - System.out.println("\t" + baseAddress + "transit/verify/sign/signature_text"); - System.out.println("\t" + baseAddress + "transit/hmac"); - System.out.println("\t" + baseAddress + "transit/verify/hmac/hmac_text"); - System.out.println("\tcurl -i -X DELETE " + baseAddress + "transit/keys"); - System.out.println("\t" + baseAddress + "transit/disable"); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/TransitService.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/TransitService.java deleted file mode 100644 index 7f1918985db..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/TransitService.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -import java.util.List; - -import io.helidon.common.Base64Value; -import io.helidon.integrations.vault.secrets.transit.CreateKey; -import io.helidon.integrations.vault.secrets.transit.Decrypt; -import io.helidon.integrations.vault.secrets.transit.DecryptBatch; -import io.helidon.integrations.vault.secrets.transit.DeleteKey; -import io.helidon.integrations.vault.secrets.transit.Encrypt; -import io.helidon.integrations.vault.secrets.transit.EncryptBatch; -import io.helidon.integrations.vault.secrets.transit.Hmac; -import io.helidon.integrations.vault.secrets.transit.Sign; -import io.helidon.integrations.vault.secrets.transit.TransitSecretsRx; -import io.helidon.integrations.vault.secrets.transit.UpdateKeyConfig; -import io.helidon.integrations.vault.secrets.transit.Verify; -import io.helidon.integrations.vault.sys.SysRx; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -class TransitService implements Service { - private static final String ENCRYPTION_KEY = "encryption-key"; - private static final String SIGNATURE_KEY = "signature-key"; - private static final Base64Value SECRET_STRING = Base64Value.create("Hello World"); - private final SysRx sys; - private final TransitSecretsRx secrets; - - TransitService(SysRx sys, TransitSecretsRx secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/enable", this::enableEngine) - .get("/keys", this::createKeys) - .delete("/keys", this::deleteKeys) - .get("/batch", this::batch) - .get("/encrypt/{text:.*}", this::encryptSecret) - .get("/decrypt/{text:.*}", this::decryptSecret) - .get("/sign", this::sign) - .get("/hmac", this::hmac) - .get("/verify/sign/{text:.*}", this::verify) - .get("/verify/hmac/{text:.*}", this::verifyHmac) - .get("/disable", this::disableEngine); - } - - private void enableEngine(ServerRequest req, ServerResponse res) { - sys.enableEngine(TransitSecretsRx.ENGINE) - .thenAccept(ignored -> res.send("Transit Secret engine enabled")) - .exceptionally(res::send); - } - - private void disableEngine(ServerRequest req, ServerResponse res) { - sys.disableEngine(TransitSecretsRx.ENGINE) - .thenAccept(ignored -> res.send("Transit Secret engine disabled")) - .exceptionally(res::send); - } - - private void createKeys(ServerRequest req, ServerResponse res) { - CreateKey.Request request = CreateKey.Request.builder() - .name(ENCRYPTION_KEY); - - secrets.createKey(request) - .flatMapSingle(ignored -> secrets.createKey(CreateKey.Request.builder() - .name(SIGNATURE_KEY) - .type("rsa-2048"))) - .forSingle(ignored -> res.send("Created keys")) - .exceptionally(res::send); - } - - private void deleteKeys(ServerRequest req, ServerResponse res) { - - secrets.updateKeyConfig(UpdateKeyConfig.Request.builder() - .name(ENCRYPTION_KEY) - .allowDeletion(true)) - .peek(ignored -> System.out.println("Updated key config")) - .flatMapSingle(ignored -> secrets.deleteKey(DeleteKey.Request.create(ENCRYPTION_KEY))) - .forSingle(ignored -> res.send("Deleted key.")) - .exceptionally(res::send); - } - - private void decryptSecret(ServerRequest req, ServerResponse res) { - String encrypted = req.path().param("text"); - - secrets.decrypt(Decrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .cipherText(encrypted)) - .forSingle(response -> res.send(String.valueOf(response.decrypted().toDecodedString()))) - .exceptionally(res::send); - } - - private void encryptSecret(ServerRequest req, ServerResponse res) { - String secret = req.path().param("text"); - - secrets.encrypt(Encrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(secret))) - .forSingle(response -> res.send(response.encrypted().cipherText())) - .exceptionally(res::send); - } - - private void hmac(ServerRequest req, ServerResponse res) { - secrets.hmac(Hmac.Request.builder() - .hmacKeyName(ENCRYPTION_KEY) - .data(SECRET_STRING)) - .forSingle(response -> res.send(response.hmac())) - .exceptionally(res::send); - } - - private void sign(ServerRequest req, ServerResponse res) { - secrets.sign(Sign.Request.builder() - .signatureKeyName(SIGNATURE_KEY) - .data(SECRET_STRING)) - .forSingle(response -> res.send(response.signature())) - .exceptionally(res::send); - } - - private void verifyHmac(ServerRequest req, ServerResponse res) { - String hmac = req.path().param("text"); - - secrets.verify(Verify.Request.builder() - .digestKeyName(ENCRYPTION_KEY) - .data(SECRET_STRING) - .hmac(hmac)) - .forSingle(response -> res.send("Valid: " + response.isValid())) - .exceptionally(res::send); - } - - private void verify(ServerRequest req, ServerResponse res) { - String signature = req.path().param("text"); - - secrets.verify(Verify.Request.builder() - .digestKeyName(SIGNATURE_KEY) - .data(SECRET_STRING) - .signature(signature)) - .forSingle(response -> res.send("Valid: " + response.isValid())) - .exceptionally(res::send); - } - - private void batch(ServerRequest req, ServerResponse res) { - String[] data = new String[] {"one", "two", "three", "four"}; - EncryptBatch.Request request = EncryptBatch.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY); - DecryptBatch.Request decryptRequest = DecryptBatch.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY); - - for (String dato : data) { - request.addEntry(EncryptBatch.BatchEntry.create(Base64Value.create(dato))); - } - secrets.encrypt(request) - .map(EncryptBatch.Response::batchResult) - .flatMapSingle(batchResult -> { - for (Encrypt.Encrypted encrypted : batchResult) { - System.out.println("Encrypted: " + encrypted.cipherText()); - decryptRequest.addEntry(DecryptBatch.BatchEntry.create(encrypted.cipherText())); - } - return secrets.decrypt(decryptRequest); - }) - .forSingle(response -> { - List base64Values = response.batchResult(); - for (int i = 0; i < data.length; i++) { - String decryptedValue = base64Values.get(i).toDecodedString(); - if (!data[i].equals(decryptedValue)) { - res.send("Data at index " + i + " is invalid. Decrypted " + decryptedValue - + ", expected: " + data[i]); - return; - } - } - res.send("Batch encryption/decryption completed"); - }) - .exceptionally(res::send); - } - -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/VaultPolicy.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/VaultPolicy.java deleted file mode 100644 index 79d9ac84ca2..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/VaultPolicy.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.integrations.vault.hcp.reactive; - -final class VaultPolicy { - private VaultPolicy() { - } - static final String POLICY = "# Enable and manage authentication methods\n" - + "path \"auth/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"update\", \"delete\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# Create, update, and delete auth methods\n" - + "path \"sys/auth/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"update\", \"delete\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# List auth methods\n" - + "path \"sys/auth\"\n" - + "{\n" - + " capabilities = [\"read\"]\n" - + "}\n" - + "\n" - + "# Enable and manage the key/value secrets engine at `secret/` path\n" - + "\n" - + "# List, create, update, and delete key/value secrets\n" - + "path \"secret/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"kv1/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"cubbyhole/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"database/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"kv/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# Manage secrets engines\n" - + "path \"sys/mounts/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# List existing secrets engines.\n" - + "path \"sys/mounts\"\n" - + "{\n" - + " capabilities = [\"read\"]\n" - + "}\n"; -} diff --git a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/package-info.java b/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/package-info.java deleted file mode 100644 index 0015ec53f90..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/java/io/helidon/examples/integrations/vault/hcp/reactive/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of Helidon integration with Hashicorp Vault in a reactive environment. - */ -package io.helidon.examples.integrations.vault.hcp.reactive; diff --git a/examples/integrations/vault/hcp-reactive/src/main/resources/application.yaml b/examples/integrations/vault/hcp-reactive/src/main/resources/application.yaml deleted file mode 100644 index 30890f33adc..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/resources/application.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server.port: 8080 - -vault: - properties: - address: "http://localhost:8200" - k8s: - address: "${vault.properties.address}" - # please change this to your k8s cluster address - # cluster-address: "https://kubernetes.docker.internal:6443" - cluster-address: "https://10.96.0.1" - auth: - k8s: - enabled: true - # this role is created in the code, must be the same value - token-role: my-role - service-account-token: "${vault.properties.k8s.service-account-token}" - app-role: - enabled: false - token: - enabled: false - token: - token: "myroot" - address: "${vault.properties.address}" - auth: - k8s: - enabled: false - app-role: - enabled: false - token: - enabled: true - approle: - address: "${vault.properties.address}" - auth: - k8s: - enabled: false - app-role: - # this is not needed, as we use a builder, - # it is here to show how this could be used to define a - # custom path for vault authentication (same can be done for k8s) - path: "customapprole" - enabled: true - token: - enabled: false \ No newline at end of file diff --git a/examples/integrations/vault/hcp-reactive/src/main/resources/logging.properties b/examples/integrations/vault/hcp-reactive/src/main/resources/logging.properties deleted file mode 100644 index d0317654f47..00000000000 --- a/examples/integrations/vault/hcp-reactive/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/vault/pom.xml b/examples/integrations/vault/pom.xml deleted file mode 100644 index ea5174c7394..00000000000 --- a/examples/integrations/vault/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 3.2.7-SNAPSHOT - - io.helidon.examples.integrations.vault - helidon-examples-integrations-vault-project - pom - Helidon Examples Integration Vault - Examples of integration with Vault. - - - hcp-reactive - hcp-cdi - - diff --git a/examples/jbatch/README.md b/examples/jbatch/README.md deleted file mode 100644 index 94539834aca..00000000000 --- a/examples/jbatch/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Helidon + jBatch - -Minimal Helidon MP + jBatch PoC. - -## Build and run - -With JDK11+ -```bash -mvn package -java -jar target/helidon-jbatch-example.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/batch -``` \ No newline at end of file diff --git a/examples/jbatch/pom.xml b/examples/jbatch/pom.xml deleted file mode 100644 index 6c33f98ca8d..00000000000 --- a/examples/jbatch/pom.xml +++ /dev/null @@ -1,138 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../applications/mp/pom.xml - - io.helidon.examples.jbatch - helidon-examples-jbatch - jbatch-example - - - 2.1.0 - 2.1.0 - 10.14.2.0 - 3.0.1 - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - jakarta.json - jakarta.json-api - - - jakarta.transaction - jakarta.transaction-api - - - jakarta.batch - jakarta.batch-api - ${version.lib.jbatch-api} - - - com.ibm.jbatch - com.ibm.jbatch.spi - ${version.lib.jbatch.container} - - - org.glassfish.jaxb - jaxb-runtime - ${version.lib.jaxb-api} - - - jakarta.xml.bind - jakarta.xml.bind-api - ${version.lib.jaxb-api} - - - - - jakarta.activation - jakarta.activation-api - runtime - - - org.jboss - jandex - runtime - true - - - com.ibm.jbatch - com.ibm.jbatch.container - ${version.lib.jbatch.container} - runtime - - - org.apache.derby - derby - ${version.lib.derby} - runtime - - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/BatchResource.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/BatchResource.java deleted file mode 100644 index 7f6b774e66d..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/BatchResource.java +++ /dev/null @@ -1,93 +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.jbatch.example; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Properties; - -import com.ibm.jbatch.spi.BatchSPIManager; -import jakarta.batch.operations.JobOperator; -import jakarta.batch.runtime.JobExecution; -import jakarta.batch.runtime.StepExecution; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - - -import static jakarta.batch.runtime.BatchRuntime.getJobOperator; - - -/** - * Trigger a batch process using resource. - */ -@Path("/batch") -@ApplicationScoped -public class BatchResource { - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private JobOperator jobOperator; - - /** - * Run a JBatch process when endpoint called. - * @return JsonObject with the result. - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject executeBatch() { - - BatchSPIManager batchSPIManager = BatchSPIManager.getInstance(); - batchSPIManager.registerPlatformMode(BatchSPIManager.PlatformMode.SE); - batchSPIManager.registerExecutorServiceProvider(new HelidonExecutorServiceProvider()); - - jobOperator = getJobOperator(); - Long executionId = jobOperator.start("myJob", new Properties()); - - return JSON.createObjectBuilder() - .add("Started a job with Execution ID: ", executionId) - .build(); - } - - /** - * Check the job status. - * @param executionId the job ID. - * @return JsonObject with status. - */ - @GET - @Path("/status/{execution-id}") - public JsonObject status(@PathParam("execution-id") Long executionId){ - JobExecution jobExecution = jobOperator.getJobExecution(executionId); - - List stepExecutions = jobOperator.getStepExecutions(executionId); - List executedSteps = new ArrayList<>(); - for (StepExecution stepExecution : stepExecutions) { - executedSteps.add(stepExecution.getStepName()); - } - - return JSON.createObjectBuilder() - .add("Steps executed", Arrays.toString(executedSteps.toArray())) - .add("Status", jobExecution.getBatchStatus().toString()) - .build(); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/HelidonExecutorServiceProvider.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/HelidonExecutorServiceProvider.java deleted file mode 100644 index d769b470c80..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/HelidonExecutorServiceProvider.java +++ /dev/null @@ -1,33 +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.jbatch.example; - -import java.util.concurrent.ExecutorService; - -import io.helidon.common.configurable.ThreadPoolSupplier; - -import com.ibm.jbatch.spi.ExecutorServiceProvider; - - -/** - * Executor service for batch processing. - */ -public class HelidonExecutorServiceProvider implements ExecutorServiceProvider { - @Override - public ExecutorService getExecutorService() { - return ThreadPoolSupplier.builder().corePoolSize(2).build().get(); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyBatchlet.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyBatchlet.java deleted file mode 100644 index 77ef6bec1cb..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyBatchlet.java +++ /dev/null @@ -1,36 +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.jbatch.example.jobs; - -import jakarta.batch.api.AbstractBatchlet; - -/** - * Batchlet example. - */ -public class MyBatchlet extends AbstractBatchlet { - - /** - * Run inside a batchlet. - * - * @return String with status. - */ - @Override - public String process() { - System.out.println("Running inside a batchlet"); - return "COMPLETED"; - } - -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyInputRecord.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyInputRecord.java deleted file mode 100644 index 7a4aab9ba66..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyInputRecord.java +++ /dev/null @@ -1,44 +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.jbatch.example.jobs; - -/** - * Example of an Input Record. - */ -public class MyInputRecord { - private int id; - - /** - * Constructor for Input Record. - * @param id - */ - public MyInputRecord(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public String toString() { - return "MyInputRecord: " + id; - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemProcessor.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemProcessor.java deleted file mode 100644 index 03cf082d0bf..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemProcessor.java +++ /dev/null @@ -1,31 +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.jbatch.example.jobs; - -import jakarta.batch.api.chunk.ItemProcessor; - -/** - * Example Item Processor. - */ -public class MyItemProcessor implements ItemProcessor { - - @Override - public MyOutputRecord processItem(Object t) { - System.out.println("processItem: " + t); - - return (((MyInputRecord) t).getId() % 2 == 0) ? null : new MyOutputRecord(((MyInputRecord) t).getId() * 2); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemReader.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemReader.java deleted file mode 100644 index a66d2626537..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemReader.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.jbatch.example.jobs; - -import java.util.StringTokenizer; - -import jakarta.batch.api.chunk.AbstractItemReader; - - -/** - * Example Item Reader. - */ -public class MyItemReader extends AbstractItemReader { - - private final StringTokenizer tokens; - - /** - * Constructor for Item Reader. - */ - public MyItemReader() { - tokens = new StringTokenizer("1,2,3,4,5,6,7,8,9,10", ","); - } - - /** - * Perform read Item. - * @return Stage result. - */ - @Override - public MyInputRecord readItem() { - if (tokens.hasMoreTokens()) { - return new MyInputRecord(Integer.valueOf(tokens.nextToken())); - } - return null; - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemWriter.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemWriter.java deleted file mode 100644 index 1d9a5927b5e..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyItemWriter.java +++ /dev/null @@ -1,32 +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.jbatch.example.jobs; - -import java.util.List; - -import jakarta.batch.api.chunk.AbstractItemWriter; - - -/** - * Example Item Writer. - */ -public class MyItemWriter extends AbstractItemWriter { - - @Override - public void writeItems(List list) { - System.out.println("writeItems: " + list); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyOutputRecord.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyOutputRecord.java deleted file mode 100644 index 8fa06b333c4..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/MyOutputRecord.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.jbatch.example.jobs; - -/** - * Example Output Processor. - */ -public class MyOutputRecord { - - private int id; - - /** - * Constructor for Output Record. - * @param id - */ - public MyOutputRecord(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public String toString() { - return "MyOutputRecord: " + id; - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/package-info.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/package-info.java deleted file mode 100644 index d9ad3724f99..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/jobs/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. - */ - -/** - * JBatch specific classes. - */ -package io.helidon.jbatch.example.jobs; diff --git a/examples/jbatch/src/main/java/io/helidon/jbatch/example/package-info.java b/examples/jbatch/src/main/java/io/helidon/jbatch/example/package-info.java deleted file mode 100644 index 41c8bfd6c14..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/jbatch/example/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. - */ - -/** - * Example application showing support for JBatch and HelidonMP. - */ -package io.helidon.jbatch.example; diff --git a/examples/jbatch/src/main/resources/META-INF/batch-jobs/myJob.xml b/examples/jbatch/src/main/resources/META-INF/batch-jobs/myJob.xml deleted file mode 100644 index 3b470f22241..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/batch-jobs/myJob.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/examples/jbatch/src/main/resources/META-INF/beans.xml b/examples/jbatch/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 0de0bc4f151..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/jbatch/src/main/resources/META-INF/helidon/serial-config.properties b/examples/jbatch/src/main/resources/META-INF/helidon/serial-config.properties deleted file mode 100644 index 8aad930d0ed..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/helidon/serial-config.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# The JBatch uses Serialization a lot, and these are all required -pattern=com.ibm.jbatch.**;jakarta.batch.runtime.BatchStatus;java.lang.Enum;\ - java.util.Properties;java.util.Hashtable;java.util.Map$Entry diff --git a/examples/jbatch/src/main/resources/META-INF/microprofile-config.properties b/examples/jbatch/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 52cd57f8f73..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Change the following to true to enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=false diff --git a/examples/jbatch/src/main/resources/logging.properties b/examples/jbatch/src/main/resources/logging.properties deleted file mode 100644 index 930fbd49781..00000000000 --- a/examples/jbatch/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Quiet Weld -org.jboss.level=WARNING diff --git a/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java b/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java deleted file mode 100644 index b7bd24702e1..00000000000 --- a/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.jbatch; - -import io.helidon.microprofile.tests.junit5.HelidonTest; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import org.junit.jupiter.api.Test; - -import jakarta.inject.Inject; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; - -import java.util.Collections; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -public class TestJBatchEndpoint { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - @Inject - private WebTarget webTarget; - - @Test - public void runJob() throws InterruptedException { - - JsonObject expectedJson = JSON.createObjectBuilder() - .add("Steps executed", "[step1, step2]") - .add("Status", "COMPLETED") - .build(); - - //Start the job - JsonObject jsonObject = webTarget - .path("/batch") - .request(MediaType.APPLICATION_JSON_TYPE) - .get(JsonObject.class); - - Integer responseJobId = jsonObject.getInt("Started a job with Execution ID: "); - assertThat(responseJobId, is(notNullValue())); - JsonObject result = null; - for (int i = 1; i < 10; i++) { - //Wait a bit for it to complete - Thread.sleep(i*1000); - - //Examine the results - result = webTarget - .path("batch/status/" + responseJobId) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(JsonObject.class); - - if (result.equals(expectedJson)){ - break; - } - - } - - assertThat(result, equalTo(expectedJson)); - } -} diff --git a/examples/k8s/zipkin.yaml b/examples/k8s/zipkin.yaml deleted file mode 100644 index 8785b945c2d..00000000000 --- a/examples/k8s/zipkin.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: zipkin - labels: - app: zipkin -spec: - selector: - matchLabels: - app: zipkin - replicas: 1 - template: - metadata: - labels: - app: zipkin - spec: - containers: - - name: zipkin - image: openzipkin/zipkin:2 - imagePullPolicy: Always - ports: - - containerPort: 9411 ---- - -apiVersion: v1 -kind: Service -metadata: - name: zipkin - labels: - app: zipkin -spec: - type: ClusterIP - selector: - app: zipkin - ports: - - port: 9411 - targetPort: 9411 - name: http - ---- - -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: zipkin-ingress -spec: - rules: - - host: localhost - http: - paths: - - path: /zipkin - pathType: Prefix - backend: - service: - name: zipkin - port: - number: 9411 diff --git a/examples/logging/jul/README.md b/examples/logging/jul/README.md deleted file mode 100644 index beab1f5d55e..00000000000 --- a/examples/logging/jul/README.md +++ /dev/null @@ -1,52 +0,0 @@ -JUL Example ---- - -This example shows how to use Java Util Logging with MDC - using Helidon API. - -The example can be built using GraalVM native image as well. - -# Running as jar - -Build this application: -```shell script -mvn clean package -``` - -Run from command line: -```shell script -java -jar target/helidon-examples-logging-jul.jar -``` - -Expected output should be similar to the following: -```text -2020.11.19 15:37:28 INFO io.helidon.common.LogConfig Thread[main,5,main]: Logging at initialization configured using classpath: /logging.properties "" -2020.11.19 15:37:28 INFO io.helidon.examples.logging.jul.Main Thread[main,5,main]: Starting up "startup" -2020.11.19 15:37:28 INFO io.helidon.examples.logging.jul.Main Thread[pool-1-thread-1,5,main]: Running on another thread "propagated" -2020.11.19 15:37:28 INFO io.helidon.common.HelidonFeatures Thread[features-thread,5,main]: Helidon SE 2.2.0 features: [Config, WebServer] "" -2020.11.19 15:37:28 INFO io.helidon.webserver.NettyWebServer Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default' started: [id: 0x8a5f5634, L:/0:0:0:0:0:0:0:0:8080] "" -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell script -mvn clean package -Pnative-image -``` - -Run from command line: -```shell script -./target/helidon-examples-logging-jul -``` - -Expected output should be similar to the following: -```text -2020.11.19 15:38:14 INFO io.helidon.common.LogConfig Thread[main,5,main]: Logging at runtime configured using classpath: /logging.properties "" -2020.11.19 15:38:14 INFO io.helidon.examples.logging.jul.Main Thread[main,5,main]: Starting up "startup" -2020.11.19 15:38:14 INFO io.helidon.examples.logging.jul.Main Thread[pool-1-thread-1,5,main]: Running on another thread "propagated" -2020.11.19 15:38:14 INFO io.helidon.common.HelidonFeatures Thread[features-thread,5,main]: Helidon SE 2.2.0 features: [Config, WebServer] "" -2020.11.19 15:38:14 INFO io.helidon.webserver.NettyWebServer Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default' started: [id: 0x2b929906, L:/0:0:0:0:0:0:0:0:8080] "" -``` \ No newline at end of file diff --git a/examples/logging/jul/pom.xml b/examples/logging/jul/pom.xml deleted file mode 100644 index 5d2d3c4a01b..00000000000 --- a/examples/logging/jul/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-jul - Helidon Examples Logging Java Util Logging - - - Example of logging and MDC using JUL - - - - io.helidon.examples.logging.jul.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-jul - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/Main.java b/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/Main.java deleted file mode 100644 index fdbff04a577..00000000000 --- a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/Main.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.logging.jul; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import io.helidon.common.LogConfig; -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Main class of the example, runnable from command line. - */ -public final class Main { - private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer.builder() - .routing(Routing.builder() - .get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.requestId())); - LOGGER.info("Running in webserver, id:"); - res.send("Hello"); - }) - .build()) - .port(8080) - .build() - .start() - .await(10, TimeUnit.SECONDS); - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - LOGGER.info("Starting up"); - - // now let's see propagation across executor service boundary - HelidonMdc.set("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(() -> { - LOGGER.info("Running on another thread"); - }); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } -} diff --git a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/package-info.java b/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/package-info.java deleted file mode 100644 index 250b9a7dc4b..00000000000 --- a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Java util logging example with Mapped diagnostics context in Helidon. - */ -package io.helidon.examples.logging.jul; diff --git a/examples/logging/jul/src/main/resources/logging.properties b/examples/logging/jul/src/main/resources/logging.properties deleted file mode 100644 index 3cb6b545c53..00000000000 --- a/examples/logging/jul/src/main/resources/logging.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.HelidonConsoleHandler - -# !thread! is replaced by Helidon with the thread name -# any %X{...} is replaced by a value from MDC -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s "%X{name}"%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO diff --git a/examples/logging/log4j/README.md b/examples/logging/log4j/README.md deleted file mode 100644 index fe820757881..00000000000 --- a/examples/logging/log4j/README.md +++ /dev/null @@ -1,56 +0,0 @@ -Log4j Example ---- - -This example shows how to use log4j with MDC (`ThreadContext`) - using Helidon API. - -The example moves all Java Util Logging to log4j. - -The example can be built using GraalVM native image as well. - -# Running as jar - -Build this application: -```shell script -mvn clean package -``` - -Run from command line: -```shell script -java -jar target/helidon-examples-logging-log4j.jar -``` - -Expected output should be similar to the following: -```text -2020-11-19 15:44:48,561 main INFO Registered Log4j as the java.util.logging.LogManager. -15:44:48.596 INFO [main] io.helidon.examples.logging.log4j.Main - Starting up "startup" -15:44:48.598 INFO [main] io.helidon.examples.logging.log4j.Main - Using JUL logger "startup" -15:44:48.600 INFO [pool-2-thread-1] io.helidon.examples.logging.log4j.Main - Running on another thread "propagated" -15:44:48.704 INFO [features-thread] io.helidon.common.HelidonFeatures - Helidon SE 2.2.0 features: [Config, WebServer] "" -15:44:48.801 INFO [nioEventLoopGroup-2-1] io.helidon.webserver.NettyWebServer - Channel '@default' started: [id: 0xa215c23d, L:/0:0:0:0:0:0:0:0:8080] "" -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell script -mvn clean package -Pnative-image -``` - -Run from command line: -```shell script -./target/helidon-examples-logging-log4j -``` - -*In native image, we can only replace loggers initialized after reconfiguration of logging system -This unfortunately means that Helidon logging would not be available* - -Expected output should be similar to the following: -```text -15:47:53.033 INFO [main] io.helidon.examples.logging.log4j.Main - Starting up "startup" -15:47:53.033 INFO [main] io.helidon.examples.logging.log4j.Main - Using JUL logger "startup" -15:47:53.033 INFO [pool-2-thread-1] io.helidon.examples.logging.log4j.Main - Running on another thread "propagated" -``` \ No newline at end of file diff --git a/examples/logging/log4j/pom.xml b/examples/logging/log4j/pom.xml deleted file mode 100644 index ee089709523..00000000000 --- a/examples/logging/log4j/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-log4j - Helidon Examples Logging Log4j - - - Example of logging and MDC using Log4j - - - - io.helidon.examples.logging.log4j.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-log4j - - - org.apache.logging.log4j - log4j-api - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-jul - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/Main.java b/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/Main.java deleted file mode 100644 index 072997e567d..00000000000 --- a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/Main.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.logging.log4j; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.appender.ConsoleAppender; -import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; - -/** - * Main class of the example, runnable from command line. - * There is a limitation of log4j in native image - we only have loggers that are - * initialized after we configure logging, which unfortunately excludes Helidon loggers. - * You would need to use JUL or slf4j to have Helidon logs combined with application logs. - */ -public final class Main { - static { - // replace JUL log manager with Log4j log manager, so we log all to it - System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); - } - - private static java.util.logging.Logger julLogger; - private static Logger logger; - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - // file based logging configuration does not work - // with native image! - configureLogging(); - // get logger after configuration - logger = LogManager.getLogger(Main.class.getName()); - julLogger = java.util.logging.Logger.getLogger(Main.class.getName()); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer.builder() - .routing(Routing.builder() - .get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.requestId())); - logger.info("Running in webserver, id:"); - res.send("Hello"); - }) - .build()) - .port(8080) - .build() - .start() - .await(10, TimeUnit.SECONDS); - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - logger.info("Starting up"); - julLogger.info("Using JUL logger"); - - // now let's see propagation across executor service boundary, we can also use Log4j's ThreadContext - ThreadContext.put("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(Main::log); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } - - private static void log() { - logger.info("Running on another thread"); - } - - private static void configureLogging() { - // configure log4j - final var builder = ConfigurationBuilderFactory.newConfigurationBuilder(); - builder.setConfigurationName("root"); - builder.setStatusLevel(Level.INFO); - final var appenderComponentBuilder = builder.newAppender("Stdout", "CONSOLE") - .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); - appenderComponentBuilder.add(builder.newLayout("PatternLayout") - .addAttribute("pattern", "%d{HH:mm:ss.SSS} %-5level [%t] %logger{36} - %msg " - + "\"%X{name}\"%n")); - builder.add(appenderComponentBuilder); - builder.add(builder.newRootLogger(Level.INFO) - .add(builder.newAppenderRef("Stdout"))); - Configurator.initialize(builder.build()); - } -} diff --git a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/package-info.java b/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/package-info.java deleted file mode 100644 index 2315e1b7116..00000000000 --- a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Log4j example with Mapped diagnostics context (ThreadContext) in Helidon. - */ -package io.helidon.examples.logging.log4j; diff --git a/examples/logging/logback-aot/README.md b/examples/logging/logback-aot/README.md deleted file mode 100644 index ccce32d5803..00000000000 --- a/examples/logging/logback-aot/README.md +++ /dev/null @@ -1,60 +0,0 @@ -Slf4j/Logback Example ---- - -This example shows how to use slf4j with MDC backed by Logback - using Helidon API. - -The example moves all Java Util Logging to slf4j and supports more advance configuration of logback. - -# AOT (native image) -To support native image, we need to use a different logback configuration at build time and at runtime. -To achieve this, we bundle `logback.xml` on classpath, and then have `logback-runtime.xml` with -configuration that requires started threads (which is not supported at build time). - -The implementation will re-configure logback (see method `setupLogging` in `Main.java). - -To see that configuration works as expected at runtime, change the log level of our package to `debug`. -Within 30 seconds the configuration should be reloaded, and next request will have two more debug messages. - -Expected output should be similar to the following (for both hotspot and native): -```text -15:40:44.240 INFO [main] i.h.examples.logging.slf4j.Main - Starting up startup -15:40:44.241 INFO [main] i.h.examples.logging.slf4j.Main - Using JUL logger startup -15:40:44.245 INFO [pool-1-thread-1] i.h.examples.logging.slf4j.Main - Running on another thread propagated -15:40:44.395 INFO [features-thread] io.helidon.common.HelidonFeatures - Helidon SE 2.2.0 features: [Config, WebServer] -15:40:44.538 INFO [nioEventLoopGroup-2-1] io.helidon.webserver.NettyWebServer - Channel '@default' started: [id: 0x8e516487, L:/0:0:0:0:0:0:0:0:8080] -``` - -The output is also logged into `helidon.log`. - -# Running as jar - -Build this application: -```shell script -mvn clean package -``` - -Run from command line: -```shell script -java -jar target/helidon-examples-logging-sfl4j.jar -``` - -Execute endpoint: -```shell -curl -i http://localhost:8080 -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell script -mvn clean package -Pnative-image -``` - -Run from command line: -```shell script -./target/helidon-examples-logging-sfl4j -``` diff --git a/examples/logging/logback-aot/logback-runtime.xml b/examples/logging/logback-aot/logback-runtime.xml deleted file mode 100644 index af7e825f273..00000000000 --- a/examples/logging/logback-aot/logback-runtime.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - helidon.log - true - false - - helidon.%d{yyyy-MM-dd}.gz - 10 - 5GB - - - - ${defaultPattern} - - - - - - 2048 - 15000 - true - true - - - - - ${defaultPattern} - - - - - - - - - - - - - - - diff --git a/examples/logging/logback-aot/pom.xml b/examples/logging/logback-aot/pom.xml deleted file mode 100644 index 8973c31116b..00000000000 --- a/examples/logging/logback-aot/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-slf4j-aot - Helidon Examples Logging Slf4j AOT - - - Example of logging and MDC using Slf4j ready for Ahead of time compilation - using GraalVM native image - - - - io.helidon.examples.logging.logback.aot.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-slf4j - - - org.slf4j - slf4j-api - - - org.slf4j - jul-to-slf4j - - - ch.qos.logback - logback-classic - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/Main.java b/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/Main.java deleted file mode 100644 index 64d8c063d85..00000000000 --- a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/Main.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.logging.logback.aot; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.joran.JoranConfigurator; -import ch.qos.logback.core.joran.spi.JoranException; -import ch.qos.logback.core.util.StatusPrinter; -import org.slf4j.ILoggerFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.slf4j.bridge.SLF4JBridgeHandler; - -/** - * Main class of the example, runnable from command line. - */ -public final class Main { - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); - private static final java.util.logging.Logger JUL_LOGGER = java.util.logging.Logger.getLogger(Main.class.getName()); - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - // use slf4j for JUL as well - setupLogging(); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer.builder() - .routing(Routing.builder() - .get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.requestId())); - LOGGER.debug("Debug message to show runtime reloading works"); - LOGGER.info("Running in webserver, id:"); - res.send("Hello") - .forSingle(ignored -> LOGGER.debug("Response sent")); - }) - .build()) - .port(8080) - .build() - .start() - .await(10, TimeUnit.SECONDS); - } - - private static void setupLogging() { - String location = System.getProperty("logback.configurationFile"); - location = (location == null) ? "logback-runtime.xml" : location; - // we cannot use anything that starts threads at build time, must re-configure here - resetLogging(location); - - SLF4JBridgeHandler.removeHandlersForRootLogger(); - SLF4JBridgeHandler.install(); - } - - private static void resetLogging(String location) { - ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); - if (loggerFactory instanceof LoggerContext) { - resetLogging(location, (LoggerContext) loggerFactory); - } else { - LOGGER.warn("Expecting a logback implementation, but got " + loggerFactory.getClass().getName()); - } - } - - private static void resetLogging(String location, LoggerContext loggerFactory) { - JoranConfigurator configurator = new JoranConfigurator(); - - configurator.setContext(loggerFactory); - loggerFactory.reset(); - - try { - configurator.doConfigure(location); - - Logger instance = LoggerFactory.getLogger(Main.class); - instance.info("Runtime logging configured from file \"{}\".", location); - StatusPrinter.print(loggerFactory); - } catch (JoranException e) { - LOGGER.warn("Failed to reload logging from " + location, e); - e.printStackTrace(); - } - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - LOGGER.info("Starting up"); - JUL_LOGGER.info("Using JUL logger"); - - // now let's see propagation across executor service boundary, we can also use Log4j's ThreadContext - MDC.put("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(Main::log); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } - - private static void log() { - LOGGER.info("Running on another thread"); - } -} diff --git a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/package-info.java b/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/package-info.java deleted file mode 100644 index 9094294a35a..00000000000 --- a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Slf4j example with Mapped diagnostics context (MDC) in Helidon ready for - * complex runtime configuration in native image. - */ -package io.helidon.examples.logging.logback.aot; diff --git a/examples/logging/logback-aot/src/main/resources/logback.xml b/examples/logging/logback-aot/src/main/resources/logback.xml deleted file mode 100644 index db7f4e49578..00000000000 --- a/examples/logging/logback-aot/src/main/resources/logback.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - %d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg %X{name}%n - - - - - - - - \ No newline at end of file diff --git a/examples/logging/pom.xml b/examples/logging/pom.xml deleted file mode 100644 index 9ddda50f514..00000000000 --- a/examples/logging/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.logging - helidon-examples-logging-project - Helidon Examples Logging - pom - - - Examples of Helidon Logging - - - - jul - log4j - slf4j - logback-aot - - diff --git a/examples/logging/slf4j/README.md b/examples/logging/slf4j/README.md deleted file mode 100644 index 3f5fae5afd2..00000000000 --- a/examples/logging/slf4j/README.md +++ /dev/null @@ -1,45 +0,0 @@ -Slf4j Example ---- - -This example shows how to use slf4j with MDC - using Helidon API. - -The example moves all Java Util Logging to slf4j - -The example can be built using GraalVM native image as well. - -Expected output should be similar to the following (for both hotspot and native): -```text -15:40:44.240 INFO [main] i.h.examples.logging.slf4j.Main - Starting up startup -15:40:44.241 INFO [main] i.h.examples.logging.slf4j.Main - Using JUL logger startup -15:40:44.245 INFO [pool-1-thread-1] i.h.examples.logging.slf4j.Main - Running on another thread propagated -15:40:44.395 INFO [features-thread] io.helidon.common.HelidonFeatures - Helidon SE 2.2.0 features: [Config, WebServer] -15:40:44.538 INFO [nioEventLoopGroup-2-1] io.helidon.webserver.NettyWebServer - Channel '@default' started: [id: 0x8e516487, L:/0:0:0:0:0:0:0:0:8080] -``` - -# Running as jar - -Build this application: -```shell script -mvn clean package -``` - -Run from command line: -```shell script -java -jar target/helidon-examples-logging-sfl4j.jar -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell script -mvn clean package -Pnative-image -``` - -Run from command line: -```shell script -./target/helidon-examples-logging-sfl4j -``` diff --git a/examples/logging/slf4j/pom.xml b/examples/logging/slf4j/pom.xml deleted file mode 100644 index cac7004e439..00000000000 --- a/examples/logging/slf4j/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-slf4j - Helidon Examples Logging Slf4j - - - Example of logging and MDC using Slf4j - - - - io.helidon.examples.logging.slf4j.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-slf4j - - - org.slf4j - slf4j-api - - - org.slf4j - jul-to-slf4j - - - ch.qos.logback - logback-classic - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/Main.java b/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/Main.java deleted file mode 100644 index 775929b7f03..00000000000 --- a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/Main.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.logging.slf4j; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.slf4j.bridge.SLF4JBridgeHandler; - -/** - * Main class of the example, runnable from command line. - */ -public final class Main { - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); - private static final java.util.logging.Logger JUL_LOGGER = java.util.logging.Logger.getLogger(Main.class.getName()); - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - // use slf4j for JUL as well - setupLogging(); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer.builder() - .routing(Routing.builder() - .get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.requestId())); - LOGGER.info("Running in webserver, id:"); - res.send("Hello"); - }) - .build()) - .port(8080) - .build() - .start() - .await(10, TimeUnit.SECONDS); - } - - private static void setupLogging() { - SLF4JBridgeHandler.removeHandlersForRootLogger(); - SLF4JBridgeHandler.install(); - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - LOGGER.info("Starting up"); - JUL_LOGGER.info("Using JUL logger"); - - // now let's see propagation across executor service boundary, we can also use Log4j's ThreadContext - MDC.put("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(Main::log); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } - - private static void log() { - LOGGER.info("Running on another thread"); - } -} diff --git a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/package-info.java b/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/package-info.java deleted file mode 100644 index 3c108cf7c60..00000000000 --- a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Slf4j example with Mapped diagnostics context (MDC) in Helidon. - */ -package io.helidon.examples.logging.slf4j; diff --git a/examples/logging/slf4j/src/main/resources/logback.xml b/examples/logging/slf4j/src/main/resources/logback.xml deleted file mode 100644 index c681f5db3a9..00000000000 --- a/examples/logging/slf4j/src/main/resources/logback.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - %d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg %X{name}%n - - - - - - - - \ No newline at end of file diff --git a/examples/media/multipart/README.md b/examples/media/multipart/README.md deleted file mode 100644 index cbe0e9fb682..00000000000 --- a/examples/media/multipart/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon SE MultiPart Example - -This example demonstrates how to use `MultiPartSupport` with both the `WebServer` - and `WebClient` APIs. - -This project implements a simple file service web application that supports uploading -and downloading files. The unit test uses the `WebClient` API to test the endpoints. - -## Build - -``` -mvn package -``` - -## Run - -First, start the server: - -``` -java -jar target/helidon-examples-microprofile-multipart.jar -``` - -Then open in your browser. diff --git a/examples/media/multipart/pom.xml b/examples/media/multipart/pom.xml deleted file mode 100644 index 2067b2b3705..00000000000 --- a/examples/media/multipart/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.media - helidon-examples-media-multipart - Helidon Examples Media Support Multipart - - - Example of a form based file upload. - - - - io.helidon.examples.media.multipart.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.media - helidon-media-multipart - - - io.helidon.media - helidon-media-jsonp - - - org.eclipse.parsson - parsson - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java deleted file mode 100644 index 8b38a604907..00000000000 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java +++ /dev/null @@ -1,102 +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. - */ -package io.helidon.examples.media.multipart; - -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Map; -import java.util.concurrent.ExecutorService; - -import io.helidon.common.configurable.ThreadPoolSupplier; -import io.helidon.common.http.DataChunk; -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.common.reactive.IoMulti; -import io.helidon.media.multipart.ContentDisposition; -import io.helidon.media.multipart.ReadableBodyPart; -import io.helidon.webserver.ResponseHeaders; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; - -/** - * File service. - */ -public final class FileService implements Service { - - private static final JsonBuilderFactory JSON_FACTORY = Json.createBuilderFactory(Map.of()); - private final FileStorage storage; - private final ExecutorService executor = ThreadPoolSupplier.create("multipart-thread-pool").get(); - - - /** - * Create a new file upload service instance. - */ - FileService() { - storage = new FileStorage(); - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/", this::list) - .get("/{fname}", this::download) - .post("/", this::upload); - } - - private void list(ServerRequest req, ServerResponse res) { - JsonArrayBuilder arrayBuilder = JSON_FACTORY.createArrayBuilder(); - storage.listFiles().forEach(arrayBuilder::add); - res.send(JSON_FACTORY.createObjectBuilder().add("files", arrayBuilder).build()); - } - - private void download(ServerRequest req, ServerResponse res) { - Path filePath = storage.lookup(req.path().param("fname")); - ResponseHeaders headers = res.headers(); - headers.contentType(MediaType.APPLICATION_OCTET_STREAM); - headers.put(Http.Header.CONTENT_DISPOSITION, ContentDisposition.builder() - .filename(filePath.getFileName().toString()) - .build() - .toString()); - res.send(filePath); - } - - private void upload(ServerRequest req, ServerResponse res) { - req.content().asStream(ReadableBodyPart.class) - .forEach(part -> { - if ("file[]".equals(part.name())) { - part.content().map(DataChunk::data) - .flatMapIterable(Arrays::asList) - .to(IoMulti.writeToFile(storage.create(part.filename())) - .executor(executor) - .build()); - } else { - // when streaming unconsumed parts needs to be drained - part.drain(); - } - }) - .onError(res::send) - .onComplete(() -> { - res.status(Http.Status.MOVED_PERMANENTLY_301); - res.headers().put(Http.Header.LOCATION, "/ui"); - res.send(); - }).ignoreElement(); - } -} diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileStorage.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileStorage.java deleted file mode 100644 index dbc229c9f07..00000000000 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileStorage.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.media.multipart; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.stream.Stream; - -import io.helidon.webserver.BadRequestException; -import io.helidon.webserver.NotFoundException; - -/** - * Simple bean to managed a directory based storage. - */ -public class FileStorage { - - private final Path storageDir; - - /** - * Create a new instance. - */ - public FileStorage() { - try { - storageDir = Files.createTempDirectory("fileupload"); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - /** - * Get the storage directory. - * - * @return directory - */ - public Path storageDir() { - return storageDir; - } - - /** - * Get the names of the files in the storage directory. - * - * @return Stream of file names - */ - public Stream listFiles() { - try { - return Files.walk(storageDir) - .filter(Files::isRegularFile) - .map(storageDir::relativize) - .map(java.nio.file.Path::toString); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - /** - * Create a new file in the storage. - * - * @param fname file name - * @return file - * @throws BadRequestException if the resolved file is not contained in the storage directory - */ - public Path create(String fname) { - Path file = storageDir.resolve(fname); - if (!file.getParent().equals(storageDir)) { - throw new BadRequestException("Invalid file name"); - } - try { - Files.createFile(file); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - return file; - } - - /** - * Lookup an existing file in the storage. - * - * @param fname file name - * @return file - * @throws NotFoundException If the resolved file does not exist - * @throws BadRequestException if the resolved file is not contained in the storage directory - */ - public Path lookup(String fname) { - Path file = storageDir.resolve(fname); - if (!file.getParent().equals(storageDir)) { - throw new BadRequestException("Invalid file name"); - } - if (!Files.exists(file)) { - throw new NotFoundException("file not found"); - } - if (!Files.isRegularFile(file)) { - throw new BadRequestException("Not a file"); - } - return file; - } -} diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/Main.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/Main.java deleted file mode 100644 index dd04076dc9e..00000000000 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/Main.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.media.multipart; - -import io.helidon.common.http.Http; -import io.helidon.common.reactive.Single; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.media.multipart.MultiPartSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -/** - * This application provides a simple file upload service with a UI to exercise multipart. - */ -public final class Main { - - private Main() { - } - - /** - * Creates new {@link Routing}. - * - * @return the new instance - */ - static Routing createRouting() { - return Routing.builder() - .any("/", (req, res) -> { - res.status(Http.Status.MOVED_PERMANENTLY_301); - res.headers().put(Http.Header.LOCATION, "/ui"); - res.send(); - }) - .register("/ui", StaticContentSupport.builder("WEB") - .welcomeFileName("index.html") - .build()) - .register("/api", new FileService()) - .build(); - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - WebServer server = WebServer.builder(createRouting()) - .port(8080) - .addMediaSupport(MultiPartSupport.create()) - .addMediaSupport(JsonpSupport.create()) - .build(); - - Single webserver = server.start(); - - // Start the server and print some info. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:" + ws.port()); - }); - - // Server threads are not demon. NO need to block. Just react. - server.whenShutdown() - .thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - - return webserver; - } - - -} diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/package-info.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/package-info.java deleted file mode 100644 index 09e93541ec5..00000000000 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon Examples Media MultiPart. - */ -package io.helidon.examples.media.multipart; diff --git a/examples/media/multipart/src/main/resources/WEB/index.html b/examples/media/multipart/src/main/resources/WEB/index.html deleted file mode 100644 index 020d42db3f8..00000000000 --- a/examples/media/multipart/src/main/resources/WEB/index.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - Helidon Examples Media Multipart - - - - - -

Uploaded files

-
- -

Upload

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

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

-
-
- -
-
Send
-
-
-
-
-
REST call /rest/messages/send/{msg}
-
-
-
Messages received from JMS over websocket
-
-
-
-
-
-            
-        
-
-
- - - - - \ No newline at end of file diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/WEB/main.css b/examples/messaging/jms-websocket-mp/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/application.yaml b/examples/messaging/jms-websocket-mp/src/main/resources/application.yaml deleted file mode 100644 index c0878fff5c8..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/resources/application.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 7001 - host: 0.0.0.0 - static.classpath: - location: /WEB - welcome: index.html - -mp.messaging: - connector.helidon-jms: - jndi: - jms-factory: ConnectionFactory - env-properties: - java.naming.factory.initial: org.apache.activemq.jndi.ActiveMQInitialContextFactory - java.naming.provider.url: tcp://127.0.0.1:61616 - - outgoing: - toJms: - connector: helidon-jms - destination: messaging-queue-topic-2 - type: queue - - incoming: - fromJms: - connector: helidon-jms - destination: messaging-test-queue-1 - session-group-id: session-group-1 - type: queue - - fromJmsSameSession: - connector: helidon-jms - destination: messaging-queue-topic-2 - session-group-id: session-group-1 - type: queue diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/logging.properties b/examples/messaging/jms-websocket-mp/src/main/resources/logging.properties deleted file mode 100644 index fc2a665a625..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/messaging/jms-websocket-se/README.md b/examples/messaging/jms-websocket-se/README.md deleted file mode 100644 index 7bc0880a588..00000000000 --- a/examples/messaging/jms-websocket-se/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Helidon Messaging with JMS Example - -## Prerequisites -* Java 17+ -* Docker -* [ActiveMQ server](../README.md) running on `localhost:61616` - -## Build & Run -1. `mvn clean install` -2. `java -jar helidon-examples-jms-websocket-se.jar` -3. Visit http://localhost:7001 - diff --git a/examples/messaging/jms-websocket-se/pom.xml b/examples/messaging/jms-websocket-se/pom.xml deleted file mode 100644 index cad7655b5e9..00000000000 --- a/examples/messaging/jms-websocket-se/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.jms - helidon-examples-jms-websocket-se - 1.0-SNAPSHOT - jms-websocket-se - - - io.helidon.examples.messaging.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.messaging - helidon-messaging - - - io.helidon.messaging.jms - helidon-messaging-jms - - - jakarta.websocket - jakarta.websocket-api - - - io.helidon.webserver - helidon-webserver-websocket - - - io.helidon.config - helidon-config-yaml - - - org.apache.activemq - activemq-client - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java deleted file mode 100644 index bb9b8a67596..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java +++ /dev/null @@ -1,113 +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. - */ - -package io.helidon.examples.messaging.se; - -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.LogManager; - -import io.helidon.config.Config; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; -import io.helidon.webserver.websocket.WebSocketRouting; - -import jakarta.websocket.server.ServerEndpointConfig; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - * @throws IOException if there are problems reading logging properties - */ - public static void main(final String[] args) throws IOException { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - * @throws IOException if there are problems reading logging properties - */ - static WebServer startServer() throws IOException { - // load logging configuration - setupLogging(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - SendingService sendingService = new SendingService(config); - - WebServer server = WebServer.builder() - .routing(r -> r - // register static content support (on "/") - .register(StaticContentSupport.builder("/WEB") - .welcomeFileName("index.html") - .build()) - // register rest endpoint for sending to Jms - .register("/rest/messages", sendingService)) - .addRouting(WebSocketRouting.builder() - // register WebSocket endpoint to push messages coming from Jms to client - .endpoint("/ws", ServerEndpointConfig.Builder.create( - WebSocketEndpoint.class, "/messages") - .build()) - .build()) - .config(config.get("server")) - .build(); - - server.start() - .thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port()); - ws.whenShutdown().thenRun(() - -> { - // Stop messaging properly - sendingService.shutdown(); - System.out.println("WEB server is DOWN. Good bye!"); - }); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - // Server threads are not daemon. No need to block. Just react. - return server; - } - - /** - * Configure logging from logging.properties file. - */ - private static void setupLogging() throws IOException { - try (InputStream is = Main.class.getResourceAsStream("/logging.properties")) { - LogManager.getLogManager().readConfiguration(is); - } - } -} diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java deleted file mode 100644 index c34984fbdb4..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.se; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Emitter; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.jms.JmsConnector; -import io.helidon.messaging.connectors.jms.Type; -import io.helidon.webserver.Routing; -import io.helidon.webserver.Service; - -import org.apache.activemq.jndi.ActiveMQInitialContextFactory; - -class SendingService implements Service { - - private final Emitter emitter; - private final Messaging messaging; - - SendingService(Config config) { - - String url = config.get("app.jms.url").asString().get(); - String destination = config.get("app.jms.destination").asString().get(); - - // Prepare channel for connecting processor -> jms connector with specific subscriber configuration, - // channel -> connector mapping is automatic when using JmsConnector.configBuilder() - Channel toJms = Channel.builder() - .subscriberConfig(JmsConnector.configBuilder() - .jndiInitialFactory(ActiveMQInitialContextFactory.class.getName()) - .jndiProviderUrl(url) - .type(Type.QUEUE) - .destination(destination) - .build() - ).build(); - - // Prepare channel for connecting emitter -> processor - Channel toProcessor = Channel.create(); - - // Prepare Jms connector, can be used by any channel - JmsConnector jmsConnector = JmsConnector.create(); - - // Prepare emitter for manual publishing to channel - emitter = Emitter.create(toProcessor); - - messaging = Messaging.builder() - .emitter(emitter) - // Processor connect two channels together - .processor(toProcessor, toJms, payload -> { - // Transforming to upper-case before sending to jms - return payload.toUpperCase(); - }) - .connector(jmsConnector) - .build() - .start(); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - // Listen for GET /example/send/{msg} - // to send it thru messaging to Jms - rules.get("/send/{msg}", (req, res) -> { - String msg = req.path().param("msg"); - System.out.println("Emitting: " + msg); - emitter.send(msg); - res.send(); - }); - } - - /** - * Gracefully terminate messaging. - */ - public void shutdown() { - messaging.stop(); - } -} diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java deleted file mode 100644 index 49c8a09a6c3..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.se; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.jms.JmsConnector; -import io.helidon.messaging.connectors.jms.Type; - -import jakarta.websocket.CloseReason; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.Session; -import org.apache.activemq.jndi.ActiveMQInitialContextFactory; - -/** - * WebSocket endpoint. - */ -public class WebSocketEndpoint extends Endpoint { - - private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName()); - - private final Map messagingRegister = new HashMap<>(); - private final Config config = Config.create(); - - @Override - public void onOpen(Session session, EndpointConfig endpointConfig) { - - System.out.println("Session " + session.getId()); - - String url = config.get("app.jms.url").asString().get(); - String destination = config.get("app.jms.destination").asString().get(); - - // Prepare channel for connecting jms connector with specific publisher configuration -> listener, - // channel -> connector mapping is automatic when using JmsConnector.configBuilder() - Channel fromJms = Channel.builder() - .name("from-jms") - .publisherConfig(JmsConnector.configBuilder() - .jndiInitialFactory(ActiveMQInitialContextFactory.class.getName()) - .jndiProviderUrl(url) - .type(Type.QUEUE) - .destination(destination) - .build() - ) - .build(); - - // Prepare Jms connector, can be used by any channel - JmsConnector jmsConnector = JmsConnector.create(); - - Messaging messaging = Messaging.builder() - .connector(jmsConnector) - .listener(fromJms, payload -> { - System.out.println("Jms says: " + payload); - // Send message received from Jms over websocket - sendTextMessage(session, payload); - }) - .build() - .start(); - - //Save the messaging instance for proper shutdown - // when websocket connection is terminated - messagingRegister.put(session.getId(), messaging); - } - - @Override - public void onClose(final Session session, final CloseReason closeReason) { - super.onClose(session, closeReason); - LOGGER.info("Closing session " + session.getId()); - // Properly stop messaging when websocket connection is terminated - Optional.ofNullable(messagingRegister.remove(session.getId())) - .ifPresent(Messaging::stop); - } - - private void sendTextMessage(Session session, String msg) { - try { - session.getBasicRemote().sendText(msg); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Message sending failed", e); - } - } -} diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java deleted file mode 100644 index 2fccac401c8..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon SE Reactive Messaging with Jms Example. - */ -package io.helidon.examples.messaging.se; diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/favicon.ico b/examples/messaging/jms-websocket-se/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/frank.png b/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - - Helidon Reactive Messaging - - - - - - - - -
-
-
- -
-
Send
-
-
-
-
-
REST call /rest/messages/send/{msg}
-
-
-
Messages received from Jms over websocket
-
-
-
-
-
-            
-        
-
-
- - - - - \ No newline at end of file diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/main.css b/examples/messaging/jms-websocket-se/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/jms-websocket-se/src/main/resources/application.yaml b/examples/messaging/jms-websocket-se/src/main/resources/application.yaml deleted file mode 100644 index 28596dd1af4..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/resources/application.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - jms: - url: tcp://127.0.0.1:61616 - destination: se-example-queue-1 - -server: - port: 7001 - host: 0.0.0.0 - static: - classpath: - location: /WEB - welcome: index.html diff --git a/examples/messaging/jms-websocket-se/src/main/resources/logging.properties b/examples/messaging/jms-websocket-se/src/main/resources/logging.properties deleted file mode 100644 index fc2a665a625..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/messaging/kafka-websocket-mp/README.md b/examples/messaging/kafka-websocket-mp/README.md deleted file mode 100644 index ad84deda0be..00000000000 --- a/examples/messaging/kafka-websocket-mp/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Helidon MP Reactive Messaging with Kafka Example - -## Prerequisites -* Docker -* Java 17+ -* [Kafka bootstrap server](../README.md) running on `localhost:9092` - -## Build & Run -1. `mvn clean install` -2. `java -jar mp-example.jar` -3. Visit http://localhost:7001 \ No newline at end of file diff --git a/examples/messaging/kafka-websocket-mp/pom.xml b/examples/messaging/kafka-websocket-mp/pom.xml deleted file mode 100644 index 4bc538b85b3..00000000000 --- a/examples/messaging/kafka-websocket-mp/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.messaging.mp - kafka-websocket-mp - 1.0-SNAPSHOT - kafka-websocket-mp - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.messaging - helidon-microprofile-messaging - - - io.helidon.messaging.kafka - helidon-messaging-kafka - - - io.helidon.microprofile.websocket - helidon-microprofile-websocket - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java b/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java deleted file mode 100644 index 989feea8c19..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.mp; - -import java.util.concurrent.SubmissionPublisher; - -import io.helidon.common.reactive.Multi; - -import jakarta.enterprise.context.ApplicationScoped; -import org.eclipse.microprofile.reactive.messaging.Incoming; -import org.eclipse.microprofile.reactive.messaging.Message; -import org.eclipse.microprofile.reactive.messaging.Outgoing; -import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; -import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; -import org.reactivestreams.FlowAdapters; -import org.reactivestreams.Publisher; - -/** - * Bean for message processing. - */ -@ApplicationScoped -public class MsgProcessingBean { - - private final SubmissionPublisher emitter = new SubmissionPublisher<>(); - private final SubmissionPublisher broadCaster = new SubmissionPublisher<>(); - - /** - * Create a publisher for the emitter. - * - * @return A Publisher from the emitter - */ - @Outgoing("multiplyVariants") - public Publisher preparePublisher() { - // Create new publisher for emitting to by this::process - return ReactiveStreams - .fromPublisher(FlowAdapters.toPublisher(Multi.create(emitter))) - .buildRs(); - } - - /** - * Returns a builder for a processor that maps a string into three variants. - * - * @return ProcessorBuilder - */ - @Incoming("multiplyVariants") - @Outgoing("toKafka") - public ProcessorBuilder> multiply() { - // Multiply to 3 variants of same message - return ReactiveStreams.builder() - .flatMap(o -> - ReactiveStreams.of( - // upper case variant - o.toUpperCase(), - // repeat twice variant - o.repeat(2), - // reverse chars 'tnairav' - new StringBuilder(o).reverse().toString()) - ).map(Message::of); - } - - /** - * Broadcasts an event. - * - * @param msg Message to broadcast - */ - @Incoming("fromKafka") - public void broadcast(String msg) { - // Broadcast to all subscribers - broadCaster.submit(msg); - } - - /** - * Subscribe new Multi to broadcasting publisher. - * - * @return new Multi subscribed to broadcaster - */ - public Multi subscribeMulti() { - return Multi.create(broadCaster); - } - - /** - * Emit a message. - * - * @param msg message to emit - */ - public void process(final String msg) { - emitter.submit(msg); - } -} diff --git a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java b/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java deleted file mode 100644 index 71630c3a38d..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.mp; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * Expose send method for publishing to messaging. - */ -@Path("rest/messages") -@RequestScoped -public class SendingResource { - private final MsgProcessingBean msgBean; - - /** - * Constructor injection of field values. - * - * @param msgBean Messaging example bean - */ - @Inject - public SendingResource(MsgProcessingBean msgBean) { - this.msgBean = msgBean; - } - - - /** - * Send message through Messaging to Kafka. - * - * @param msg message to process - */ - @Path("/send/{msg}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public void getSend(@PathParam("msg") String msg) { - msgBean.process(msg); - } -} diff --git a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java b/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java deleted file mode 100644 index 757f450b5f6..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.mp; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.reactive.Single; - -import jakarta.inject.Inject; -import jakarta.websocket.CloseReason; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -/** - * Register all WebSocket connection as subscribers - * of broadcasting {@link java.util.concurrent.SubmissionPublisher} - * in the {@link MsgProcessingBean}. - *

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

-
-
- -
-
Send
-
-
-
-
-
REST call /rest/messages/send/{msg}
-
-
-
Messages received from Kafka over websocket
-
-
-
-
-
-            
-        
-
-
- - - - - \ No newline at end of file diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/main.css b/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/logging.properties b/examples/messaging/kafka-websocket-mp/src/main/resources/logging.properties deleted file mode 100644 index c81e423cb17..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Kafka client has exhaustive logs -org.apache.kafka.clients.level=WARNING -org.apache.kafka.clients.consumer.ConsumerConfig.level=SEVERE -org.apache.kafka.clients.producer.ProducerConfig.level=SEVERE diff --git a/examples/messaging/kafka-websocket-se/README.md b/examples/messaging/kafka-websocket-se/README.md deleted file mode 100644 index 604aa5cf4b2..00000000000 --- a/examples/messaging/kafka-websocket-se/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Helidon Messaging with Kafka Examples - -## Prerequisites -* Java 17+ -* Docker -* [Kafka bootstrap server](../README.md) running on `localhost:9092` - -## Build & Run -1. `mvn clean install` -2. `java -jar se-example.jar` -3. Visit http://localhost:7001 - diff --git a/examples/messaging/kafka-websocket-se/pom.xml b/examples/messaging/kafka-websocket-se/pom.xml deleted file mode 100644 index 8881ffa0721..00000000000 --- a/examples/messaging/kafka-websocket-se/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.messaging.se - kafka-websocket-se - 1.0-SNAPSHOT - kafka-websocket-se - - - io.helidon.examples.messaging.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.messaging - helidon-messaging - - - io.helidon.messaging.kafka - helidon-messaging-kafka - - - jakarta.websocket - jakarta.websocket-api - - - io.helidon.webserver - helidon-webserver-websocket - - - io.helidon.config - helidon-config-yaml - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java deleted file mode 100644 index 270a58c9fa4..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java +++ /dev/null @@ -1,99 +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. - */ - -package io.helidon.examples.messaging.se; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; -import io.helidon.webserver.websocket.WebSocketRouting; - -import jakarta.websocket.server.ServerEndpointConfig; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - */ - static WebServer startServer() { - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - SendingService sendingService = new SendingService(config); - - WebServer server = WebServer.builder() - .routing(r -> r - // register static content support (on "/") - .register(StaticContentSupport.builder("/WEB") - .welcomeFileName("index.html") - .build()) - // register rest endpoint for sending to Kafka - .register("/rest/messages", sendingService) - ) - // register WebSocket endpoint to push messages coming from Kafka to client - .addRouting(WebSocketRouting.builder() - .endpoint("/ws", ServerEndpointConfig.Builder.create( - WebSocketEndpoint.class, "/messages") - .build()) - .build()) - .config(config.get("server")) - .build(); - - server.start() - .thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port()); - ws.whenShutdown().thenRun(() - -> { - // Stop messaging properly - sendingService.shutdown(); - System.out.println("WEB server is DOWN. Good bye!"); - }); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - // Server threads are not daemon. No need to block. Just react. - return server; - } -} diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java deleted file mode 100644 index bf499327d30..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.se; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Emitter; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.kafka.KafkaConnector; -import io.helidon.webserver.Routing; -import io.helidon.webserver.Service; - -import org.apache.kafka.common.serialization.StringSerializer; - -class SendingService implements Service { - - private final Emitter emitter; - private final Messaging messaging; - - SendingService(Config config) { - - String kafkaServer = config.get("app.kafka.bootstrap.servers").asString().get(); - String topic = config.get("app.kafka.topic").asString().get(); - - // Prepare channel for connecting processor -> kafka connector with specific subscriber configuration, - // channel -> connector mapping is automatic when using KafkaConnector.configBuilder() - Channel toKafka = Channel.builder() - .subscriberConfig(KafkaConnector.configBuilder() - .bootstrapServers(kafkaServer) - .topic(topic) - .keySerializer(StringSerializer.class) - .valueSerializer(StringSerializer.class) - .build() - ).build(); - - // Prepare channel for connecting emitter -> processor - Channel toProcessor = Channel.create(); - - // Prepare Kafka connector, can be used by any channel - KafkaConnector kafkaConnector = KafkaConnector.create(); - - // Prepare emitter for manual publishing to channel - emitter = Emitter.create(toProcessor); - - messaging = Messaging.builder() - .emitter(emitter) - // Processor connect two channels together - .processor(toProcessor, toKafka, payload -> { - // Transforming to upper-case before sending to kafka - return payload.toUpperCase(); - }) - .connector(kafkaConnector) - .build() - .start(); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - // Listen for GET /example/send/{msg} - // to send it thru messaging to Kafka - rules.get("/send/{msg}", (req, res) -> { - String msg = req.path().param("msg"); - System.out.println("Emitting: " + msg); - emitter.send(msg); - res.send(); - }); - } - - /** - * Gracefully terminate messaging. - */ - public void shutdown() { - messaging.stop(); - } -} diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java deleted file mode 100644 index 4ea8ed6d7b0..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.se; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.kafka.KafkaConfigBuilder; -import io.helidon.messaging.connectors.kafka.KafkaConnector; - -import jakarta.websocket.CloseReason; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.Session; -import org.apache.kafka.common.serialization.StringDeserializer; - -/** - * Web socket endpoint. - */ -public class WebSocketEndpoint extends Endpoint { - - private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName()); - - private final Map messagingRegister = new HashMap<>(); - private final Config config = Config.create(); - - @Override - public void onOpen(Session session, EndpointConfig endpointConfig) { - - System.out.println("Session " + session.getId()); - - String kafkaServer = config.get("app.kafka.bootstrap.servers").asString().get(); - String topic = config.get("app.kafka.topic").asString().get(); - - // Prepare channel for connecting kafka connector with specific publisher configuration -> listener, - // channel -> connector mapping is automatic when using KafkaConnector.configBuilder() - Channel fromKafka = Channel.builder() - .name("from-kafka") - .publisherConfig(KafkaConnector.configBuilder() - .bootstrapServers(kafkaServer) - .groupId("example-group-" + session.getId()) - .topic(topic) - .autoOffsetReset(KafkaConfigBuilder.AutoOffsetReset.LATEST) - .enableAutoCommit(true) - .keyDeserializer(StringDeserializer.class) - .valueDeserializer(StringDeserializer.class) - .build() - ) - .build(); - - // Prepare Kafka connector, can be used by any channel - KafkaConnector kafkaConnector = KafkaConnector.create(); - - Messaging messaging = Messaging.builder() - .connector(kafkaConnector) - .listener(fromKafka, payload -> { - System.out.println("Kafka says: " + payload); - // Send message received from Kafka over websocket - sendTextMessage(session, payload); - }) - .build() - .start(); - - //Save the messaging instance for proper shutdown - // when websocket connection is terminated - messagingRegister.put(session.getId(), messaging); - } - - @Override - public void onClose(final Session session, final CloseReason closeReason) { - super.onClose(session, closeReason); - LOGGER.info("Closing session " + session.getId()); - // Properly stop messaging when websocket connection is terminated - Optional.ofNullable(messagingRegister.remove(session.getId())) - .ifPresent(Messaging::stop); - } - - private void sendTextMessage(Session session, String msg) { - try { - session.getBasicRemote().sendText(msg); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Message sending failed", e); - } - } -} diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java deleted file mode 100644 index d67f74ad03f..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon SE Reactive Messaging with Kafka Example. - */ -package io.helidon.examples.messaging.se; diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/favicon.ico b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/frank.png b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - - Helidon Reactive Messaging - - - - - - - - -
-
-
- -
-
Send
-
-
-
-
-
REST call /rest/messages/send/{msg}
-
-
-
Messages received from Kafka over websocket
-
-
-
-
-
-            
-        
-
-
- - - - - \ No newline at end of file diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/main.css b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/application.yaml b/examples/messaging/kafka-websocket-se/src/main/resources/application.yaml deleted file mode 100644 index e5e6f96c0f7..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/resources/application.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - kafka: - bootstrap.servers: localhost:9092 - topic: messaging-test-topic-1 - -server: - port: 7001 - host: 0.0.0.0 - static: - classpath: - location: /WEB - welcome: index.html diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/logging.properties b/examples/messaging/kafka-websocket-se/src/main/resources/logging.properties deleted file mode 100644 index fc2a665a625..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/messaging/kafkaConsume.sh b/examples/messaging/kafkaConsume.sh deleted file mode 100755 index da1c55c6ada..00000000000 --- a/examples/messaging/kafkaConsume.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -TOPIC="messaging-test-topic-1" -SERVER="localhost:9092" -CONTAINER="helidon_kafka" - -if [ -z "$1" ]; then - echo "No argument supplied, defaulting to topic ${TOPIC}" -else - TOPIC="$1" -fi - -docker exec -it ${CONTAINER} sh -c \ -"/opt/kafka/bin/kafka-console-consumer.sh --topic ${TOPIC} --bootstrap-server ${SERVER}" diff --git a/examples/messaging/kafkaProduce.sh b/examples/messaging/kafkaProduce.sh deleted file mode 100755 index 7e7a02a8bb4..00000000000 --- a/examples/messaging/kafkaProduce.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -TOPIC="messaging-test-topic-1" -SERVER="localhost:9092" -CONTAINER="helidon_kafka" - -if [ -z "$1" ]; then - echo "No argument supplied, defaulting to topic ${TOPIC}" -else - TOPIC="$1" -fi - -docker exec -it ${CONTAINER} sh -c \ -"/opt/kafka/bin/kafka-console-producer.sh --topic ${TOPIC} --bootstrap-server ${SERVER}" diff --git a/examples/messaging/kafkaRun.sh b/examples/messaging/kafkaRun.sh deleted file mode 100755 index 4883e9dbc9f..00000000000 --- a/examples/messaging/kafkaRun.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -if [[ "$(docker images -q helidon-test-kafka 2>/dev/null)" == "" ]]; then - # helidon:test-kafka not found, build it - docker build ./docker/kafka -t helidon-test-kafka -f ./docker/kafka/Dockerfile.kafka -fi - -if [ ! "$(docker ps -q -f name=helidon_kafka)" ]; then - if [ "$(docker ps -aq -f status=exited -f name=helidon_kafka)" ]; then - # Clean up exited container - docker rm helidon_kafka - fi - # Run test Kafka in new container, stop it by pressing Ctrl+C - docker run -it \ - --rm \ - --publish 2181:2181 \ - --publish 29092:9092 \ - --publish 9092:29092 \ - --name helidon_kafka \ - helidon-test-kafka -fi diff --git a/examples/messaging/oracle-aq-websocket-mp/README.md b/examples/messaging/oracle-aq-websocket-mp/README.md deleted file mode 100644 index acf5e4f4dad..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Helidon Messaging with Oracle AQ Example - -## Prerequisites -* Java 17+ -* Docker -* [Oracle database](../README.md) running on `localhost:1521` - -## Build & Run -1. `mvn clean install` -2. `java -jar aq-websocket-mp.jar` -3. Visit http://localhost:7001 - diff --git a/examples/messaging/oracle-aq-websocket-mp/pom.xml b/examples/messaging/oracle-aq-websocket-mp/pom.xml deleted file mode 100644 index 59930804ce3..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.messaging.aq - aq-websocket-mp - 1.0-SNAPSHOT - oracle-aq-websocket-mp - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.messaging - helidon-microprofile-messaging - - - io.helidon.messaging.aq - helidon-messaging-aq - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-ucp - runtime - - - io.helidon.microprofile.websocket - helidon-microprofile-websocket - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java b/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java deleted file mode 100644 index 4082f739462..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java +++ /dev/null @@ -1,131 +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. - */ - -package io.helidon.examples.messaging.mp; - -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.SubmissionPublisher; - -import io.helidon.common.reactive.BufferedEmittingPublisher; -import io.helidon.common.reactive.Multi; -import io.helidon.messaging.connectors.aq.AqMessage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.jms.JMSException; -import jakarta.jms.MapMessage; -import org.eclipse.microprofile.reactive.messaging.Acknowledgment; -import org.eclipse.microprofile.reactive.messaging.Incoming; -import org.eclipse.microprofile.reactive.messaging.Outgoing; -import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; -import org.reactivestreams.FlowAdapters; -import org.reactivestreams.Publisher; - -/** - * Bean for message processing. - */ -@ApplicationScoped -public class MsgProcessingBean { - - private final BufferedEmittingPublisher emitter = BufferedEmittingPublisher.create(); - private final SubmissionPublisher broadCaster = new SubmissionPublisher<>(); - - /** - * Create a publisher for the emitter. - * - * @return A Publisher from the emitter - */ - @Outgoing("to-queue-1") - public Publisher toFirstQueue() { - // Create new publisher for emitting to by this::process - return ReactiveStreams - .fromPublisher(FlowAdapters.toPublisher(emitter)) - .buildRs(); - } - - /** - * Example of resending message from one queue to another and logging the payload to DB in the process. - * - * @param msg received message - * @return future of the sent message - */ - @Incoming("from-queue-1") - @Outgoing("to-queue-2") - //Leave commit by ack to outgoing connector - @Acknowledgment(Acknowledgment.Strategy.NONE) - public CompletionStage> betweenQueues(AqMessage msg) { - return CompletableFuture.supplyAsync(() -> { - try { - PreparedStatement statement = msg.getDbConnection() - .prepareStatement("INSERT INTO frank.message_log (message) VALUES (?)"); - statement.setString(1, msg.getPayload()); - statement.executeUpdate(); - } catch (SQLException e) { - //Gets caught by messaging engine and translated to onError signal - throw new RuntimeException("Error when saving message to log table.", e); - } - return msg; - }); - } - - /** - * Broadcasts an event. - * - * @param msg Message to broadcast - * @return completed completion stage - */ - @Incoming("from-queue-2") - public CompletionStage fromSecondQueue(AqMessage msg) { - // Broadcast to all subscribers - broadCaster.submit(msg.getPayload()); - return CompletableFuture.completedFuture(null); - } - - /** - * Example of receiving a byte message. - * - * @param bytes received byte array - */ - @Incoming("from-byte-queue") - public void fromByteQueue(byte[] bytes) { - broadCaster.submit(new String(bytes)); - } - - /** - * Example of receiving a map message. - * - * @param msg received JMS MapMessage - * @throws JMSException when error arises during work with JMS message - */ - @Incoming("from-map-queue") - public void fromMapQueue(MapMessage msg) throws JMSException { - String head = msg.getString("head"); - byte[] body = msg.getBytes("body"); - String tail = msg.getString("tail"); - broadCaster.submit(String.join(" ", List.of(head, new String(body), tail))); - } - - Multi subscribeMulti() { - return Multi.create(broadCaster).log(); - } - - void process(final String msg) { - emitter.emit(msg); - } -} diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java b/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java deleted file mode 100644 index 7000c579aeb..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.mp; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * Expose send method for publishing to messaging. - */ -@Path("rest/messages") -@RequestScoped -public class SendingResource { - private final MsgProcessingBean msgBean; - - /** - * Constructor injection of field values. - * - * @param msgBean Messaging example bean - */ - @Inject - public SendingResource(MsgProcessingBean msgBean) { - this.msgBean = msgBean; - } - - /** - * Send message through Messaging to JMS. - * - * @param msg message to process - */ - @Path("/send/{msg}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public void getSend(@PathParam("msg") String msg) { - msgBean.process(msg); - } -} diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java b/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java deleted file mode 100644 index 757f450b5f6..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.messaging.mp; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.reactive.Single; - -import jakarta.inject.Inject; -import jakarta.websocket.CloseReason; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -/** - * Register all WebSocket connection as subscribers - * of broadcasting {@link java.util.concurrent.SubmissionPublisher} - * in the {@link MsgProcessingBean}. - *

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

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

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

- * @see io.helidon.examples.metrics.exemplar.Main - */ -package io.helidon.examples.metrics.exemplar; diff --git a/examples/metrics/exemplar/src/main/resources/application.yaml b/examples/metrics/exemplar/src/main/resources/application.yaml deleted file mode 100644 index 3f2f36804f5..00000000000 --- a/examples/metrics/exemplar/src/main/resources/application.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 -tracing: - service: "hello-world" diff --git a/examples/metrics/exemplar/src/main/resources/logging.properties b/examples/metrics/exemplar/src/main/resources/logging.properties deleted file mode 100644 index aced7e48602..00000000000 --- a/examples/metrics/exemplar/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/metrics/exemplar/src/test/java/io/helidon/examples/metrics/exemplar/MainTest.java b/examples/metrics/exemplar/src/test/java/io/helidon/examples/metrics/exemplar/MainTest.java deleted file mode 100644 index 9e3696251c4..00000000000 --- a/examples/metrics/exemplar/src/test/java/io/helidon/examples/metrics/exemplar/MainTest.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.metrics.exemplar; - -import java.io.LineNumberReader; -import java.io.StringReader; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertLinesMatch; - -public class MainTest { - - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - - static { - TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - private static WebServer startTheServer(boolean isStrictExemplars) { - return Main.startServer(isStrictExemplars).await(); - } - - private static WebServer startTheServer() { - return Main.startServer("test-app.yaml").await(); - } - - private static void shutdownServer(WebServer webServer) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - - private static WebClient webClient(WebServer webServer) { - return WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @Test - public void testHelloWorld() { - WebServer webServer = startTheServer(true); - WebClient webClient = webClient(webServer); - try { - JsonObject jsonObject; - WebClientResponse response; - - jsonObject = webClient.get() - .path("/greet") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello World!")); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello Joe!")); - - response = webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .await(); - assertThat(response.status().code(), is(204)); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hola Joe!")); - - response = webClient.get() - .path("/metrics") - .request() - .await(); - assertThat(response.status().code(), is(200)); - } finally { - shutdownServer(webServer); - } - } - - @ParameterizedTest - @ValueSource(booleans = {true, false}) - void testMetricsExemplars(boolean isStrictExemplars) { - WebServer webServer = startTheServer(isStrictExemplars); - WebClient webClient = webClient(webServer); - try { - WebClientResponse response; - - String get = webClient.get() - .path("/greet") - .request(String.class) - .await(); - - assertThat(get, containsString("Hello World!")); - - get = webClient.get() - .path("/greet/Joe") - .request(String.class) - .await(); - - assertThat(get, containsString("Hello Joe!")); - - String openMetricsOutput = webClient.get() - .path("/metrics/application") - .request(String.class) - .await(); - - LineNumberReader reader = new LineNumberReader(new StringReader(openMetricsOutput)); - List returnedLines = reader.lines() - .collect(Collectors.toList()); - - List expected = List.of(">> skip to timer total >>", - "# TYPE application_" + GreetService.TIMER_FOR_GETS + "_mean_seconds gauge", - valueMatcher("mean", isStrictExemplars), - ">> end of output >>"); - assertLinesMatch(expected, returnedLines, GreetService.TIMER_FOR_GETS + "_mean_seconds TYPE and value"); - - expected = List.of(">> skip to max >>", - "# TYPE application_" + GreetService.TIMER_FOR_GETS + "_max_seconds gauge", - valueMatcher("max", isStrictExemplars), - ">> end of output >>"); - assertLinesMatch(expected, returnedLines, GreetService.TIMER_FOR_GETS + "_max_seconds TYPE and value"); - } finally { - webServer.shutdown().await(10, TimeUnit.SECONDS); - } - } - - @Test - void testConfiguredLaxExemplars() { - WebServer webServer = startTheServer(); - WebClient webClient = webClient(webServer); - try { - WebClientResponse response; - - String get = webClient.get() - .path("/greet") - .request(String.class) - .await(); - - assertThat(get, containsString("Hello World!")); - - get = webClient.get() - .path("/greet/Joe") - .request(String.class) - .await(); - - assertThat(get, containsString("Hello Joe!")); - - String openMetricsOutput = webClient.get() - .path("/metrics/application") - .request(String.class) - .await(); - - LineNumberReader reader = new LineNumberReader(new StringReader(openMetricsOutput)); - List returnedLines = reader.lines() - .collect(Collectors.toList()); - - List expected = List.of(">> skip to timer total >>", - "# TYPE application_" + GreetService.TIMER_FOR_GETS + "_mean_seconds gauge", - valueMatcher("mean", false), - ">> end of output >>"); - assertLinesMatch(expected, returnedLines, GreetService.TIMER_FOR_GETS + "_mean_seconds TYPE and value"); - - expected = List.of(">> skip to max >>", - "# TYPE application_" + GreetService.TIMER_FOR_GETS + "_max_seconds gauge", - valueMatcher("max", false), - ">> end of output >>"); - assertLinesMatch(expected, returnedLines, GreetService.TIMER_FOR_GETS + "_max_seconds TYPE and value"); - } finally { - webServer.shutdown().await(10, TimeUnit.SECONDS); - } - } - - private static String valueMatcher(String statName, boolean isStrictExemplar) { - // application_timerForGets_mean_seconds 0.010275403147594316 # {trace_id="cfd13196e6a9fb0c"} 0.002189822 1617799841.963000 - return "application_" + GreetService.TIMER_FOR_GETS - + "_" + statName + "_seconds [\\d\\.]+" - + (isStrictExemplar ? "" : " # \\{trace_id=\"[^\"]+\"} .+"); - } -} diff --git a/examples/metrics/exemplar/src/test/resources/test-app.yaml b/examples/metrics/exemplar/src/test/resources/test-app.yaml deleted file mode 100644 index 24490c20d30..00000000000 --- a/examples/metrics/exemplar/src/test/resources/test-app.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 -tracing: - service: "hello-world" -metrics: - registries: - - type: application - exemplars: - strict: false diff --git a/examples/metrics/filtering/mp/pom.xml b/examples/metrics/filtering/mp/pom.xml deleted file mode 100644 index e6b3f482f1f..00000000000 --- a/examples/metrics/filtering/mp/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - 4.0.0 - - io.helidon.examples.metrics.filtering - helidon-examples-metrics-filtering-mp - Helidon Examples Metrics MP Filtering - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.media - helidon-media-jsonb - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - check-for-inflight-with-config-settings - - test - - - - true - - - - - - - - diff --git a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetResource.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetResource.java deleted file mode 100644 index 53422776139..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetResource.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.metrics.filtering.mp; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.Timed; - -/** - * A simple JAX-RS resource to greet you with filtered metrics support. - */ -@Path("/greet") -@RequestScoped -public class GreetResource { - - static final String TIMER_FOR_GETS = "timerForGets"; - static final String COUNTER_FOR_PERSONALIZED_GREETINGS = "counterForPersonalizedGreetings"; - - /** - * The greeting message provider. - */ - private final GreetingProvider greetingProvider; - - /** - * Using constructor injection to get a configuration property. - * By default this gets the value from META-INF/microprofile-config - * - * @param greetingConfig the configured greeting message - */ - @Inject - public GreetResource(GreetingProvider greetingConfig) { - this.greetingProvider = greetingConfig; - } - - /** - * Return a worldly greeting message. - * - * @return {@link jakarta.json.JsonObject} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - @Timed(name = TIMER_FOR_GETS, absolute = true) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link jakarta.json.JsonObject} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - @Timed(name = TIMER_FOR_GETS, absolute = true) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Counted(name = COUNTER_FOR_PERSONALIZED_GREETINGS, absolute = true) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingMessage.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingMessage.java deleted file mode 100644 index e0b889165e9..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.metrics.filtering.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingProvider.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingProvider.java deleted file mode 100644 index fff218cf5e3..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.metrics.filtering.mp; - -import java.util.concurrent.atomic.AtomicReference; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Provider for greeting message. - */ -@ApplicationScoped -public class GreetingProvider { - private final AtomicReference message = new AtomicReference<>(); - - /** - * Create a new greeting provider, reading the message from configuration. - * - * @param message greeting to use - */ - @Inject - public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) { - this.message.set(message); - } - - String getMessage() { - return message.get(); - } - - void setMessage(String message) { - this.message.set(message); - } -} diff --git a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/package-info.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/package-info.java deleted file mode 100644 index 8b9fae9f18a..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon MicroProfile metrics filtering example. - */ -package io.helidon.examples.metrics.filtering.mp; diff --git a/examples/metrics/filtering/mp/src/main/resources/META-INF/beans.xml b/examples/metrics/filtering/mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/metrics/filtering/mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/metrics/filtering/mp/src/main/resources/META-INF/microprofile-config.properties b/examples/metrics/filtering/mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index b7f79348e58..00000000000 --- a/examples/metrics/filtering/mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -app.greeting=Hello - -# Override configuration to use a random port for the unit tests -config_ordinal=1000 -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -metrics.registries.0.type = application -metrics.registries.0.filter.exclude = .*Gets diff --git a/examples/metrics/filtering/mp/src/main/resources/logging.properties b/examples/metrics/filtering/mp/src/main/resources/logging.properties deleted file mode 100644 index 8fc59d05c12..00000000000 --- a/examples/metrics/filtering/mp/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.cors.level=INFO diff --git a/examples/metrics/filtering/mp/src/test/java/io/helidon/examples/metrics/filtering/mp/MainTest.java b/examples/metrics/filtering/mp/src/test/java/io/helidon/examples/metrics/filtering/mp/MainTest.java deleted file mode 100644 index b183bb405b5..00000000000 --- a/examples/metrics/filtering/mp/src/test/java/io/helidon/examples/metrics/filtering/mp/MainTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.metrics.filtering.mp; - -import java.time.Duration; - -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Timer; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -@HelidonTest -public class MainTest { - - @Inject - private MetricRegistry appRegistry; - - @Test - void checkEnabledMetric() { - Counter personalizedGreetingsCounter = appRegistry.counter(GreetResource.COUNTER_FOR_PERSONALIZED_GREETINGS); - long before = personalizedGreetingsCounter.getCount(); - personalizedGreetingsCounter.inc(); - assertThat("Enabled counter value change", - personalizedGreetingsCounter.getCount() - before, is(1L)); - } - - @Test - void checkDisabledMetric() { - Timer getsTimer = appRegistry.timer(GreetResource.TIMER_FOR_GETS); - long before = getsTimer.getCount(); - getsTimer.update(Duration.ofSeconds(1)); - assertThat("Disabled timer value change", - getsTimer.getCount() - before, - is(0L)); - } -} diff --git a/examples/metrics/filtering/pom.xml b/examples/metrics/filtering/pom.xml deleted file mode 100644 index 8d148d48b43..00000000000 --- a/examples/metrics/filtering/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - helidon-examples-metrics-project - io.helidon.examples - 3.2.7-SNAPSHOT - - 4.0.0 - pom - - helidon-examples-metrics-filtering - Helidon Metrics Filtering Examples - - - se - mp - - diff --git a/examples/metrics/filtering/se/pom.xml b/examples/metrics/filtering/se/pom.xml deleted file mode 100644 index 31f844940df..00000000000 --- a/examples/metrics/filtering/se/pom.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - 4.0.0 - - io.helidon.examples.metrics.filtering - helidon-examples-metrics-se - Helidon Examples Metrics SE Filtering - - io.helidon.examples.metrics.filtering.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - io.helidon.config - helidon-config-yaml - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - check-for-inflight-with-config-settings - - test - - - - true - - - - - - - - diff --git a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/GreetService.java b/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/GreetService.java deleted file mode 100644 index 0604f7641ef..00000000000 --- a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/GreetService.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.metrics.filtering.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.Metadata; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.MetricType; -import org.eclipse.microprofile.metrics.MetricUnits; -import org.eclipse.microprofile.metrics.Timer; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); - - static final String TIMER_FOR_GETS = "timerForGets"; - static final String COUNTER_FOR_PERSONALIZED_GREETINGS = "counterForPersonalizedGreetings"; - - private final Timer timerForGets; - - private final Counter personalizedGreetingsCounter; - - private final Config config; - - private final MetricRegistry appRegistry; - - GreetService(Config config, MetricRegistry appRegistry) { - this.config = config; - this.appRegistry = appRegistry; - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - MetricRegistry registry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); - Metadata metadata = Metadata.builder() - .withName(TIMER_FOR_GETS) - .withUnit(MetricUnits.NANOSECONDS) - .withType(MetricType.TIMER) - .build(); - timerForGets = registry.timer(metadata); - - metadata = Metadata.builder() - .withName(COUNTER_FOR_PERSONALIZED_GREETINGS) - .withUnit(MetricUnits.NONE) - .withType(MetricType.COUNTER) - .build(); - personalizedGreetingsCounter = registry.counter(metadata); - } - - /** - * A service registers itself by updating the routing rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::timeGet, this::getDefaultMessageHandler) - .get("/{name}", this::countPersonalized, this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - if (ex.getCause() instanceof JsonException){ - - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } - - private void timeGet(ServerRequest request, ServerResponse response) { - timerForGets.time((Runnable) request::next); - } - - private void countPersonalized(ServerRequest request, ServerResponse response) { - personalizedGreetingsCounter.inc(); - request.next(); - } -} diff --git a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/Main.java b/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/Main.java deleted file mode 100644 index 2835b924a40..00000000000 --- a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/Main.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.metrics.filtering.se; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.api.MetricsSettings; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.metrics.api.RegistryFilterSettings; -import io.helidon.metrics.api.RegistrySettings; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import org.eclipse.microprofile.metrics.MetricRegistry; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link io.helidon.webserver.WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // Ignore the "gets" timer. - RegistryFilterSettings.Builder registryFilterSettingsBuilder = RegistryFilterSettings.builder() - .exclude(GreetService.TIMER_FOR_GETS); - - RegistrySettings.Builder registrySettingsBuilder = RegistrySettings.builder() - .filterSettings(registryFilterSettingsBuilder); - - MetricsSettings.Builder metricsSettingsBuilder = MetricsSettings.builder() - .registrySettings(MetricRegistry.Type.APPLICATION, registrySettingsBuilder.build()); - - WebServer server = WebServer.builder() - .routing(createRouting(config, metricsSettingsBuilder)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link io.helidon.webserver.Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config, MetricsSettings.Builder metricsSettingsBuilder) { - MetricsSupport metricsSupport = MetricsSupport.builder() - .metricsSettings(metricsSettingsBuilder) - .build(); - MetricRegistry appRegistry = RegistryFactory.getInstance(metricsSettingsBuilder.build()) - .getRegistry(MetricRegistry.Type.APPLICATION); - - GreetService greetService = new GreetService(config, appRegistry); - - return Routing.builder() - .register(metricsSupport) // Metrics at "/metrics" - .register("/greet", greetService) - .build(); - } -} diff --git a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/package-info.java b/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/package-info.java deleted file mode 100644 index 8b75421b62e..00000000000 --- a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Helidon SE example of controlling metrics using filtering. - */ -package io.helidon.examples.metrics.filtering.se; diff --git a/examples/metrics/filtering/se/src/main/resources/application.yaml b/examples/metrics/filtering/se/src/main/resources/application.yaml deleted file mode 100644 index 7625ea2f293..00000000000 --- a/examples/metrics/filtering/se/src/main/resources/application.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 -# experimental: -# http2: -# enable: true -# max-content-length: 16384 -tracing: - service: "hello-world" diff --git a/examples/metrics/filtering/se/src/main/resources/logging.properties b/examples/metrics/filtering/se/src/main/resources/logging.properties deleted file mode 100644 index aced7e48602..00000000000 --- a/examples/metrics/filtering/se/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/metrics/filtering/se/src/test/java/io/helidon/examples/metrics/filtering/se/MainTest.java b/examples/metrics/filtering/se/src/test/java/io/helidon/examples/metrics/filtering/se/MainTest.java deleted file mode 100644 index 9013aa322b6..00000000000 --- a/examples/metrics/filtering/se/src/test/java/io/helidon/examples/metrics/filtering/se/MainTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.metrics.filtering.se; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; - -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - - static { - TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - @BeforeAll - public static void startTheServer() { - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - public static void stopServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - @Test - public void testHelloWorld() { - JsonObject jsonObject; - WebClientResponse response; - - jsonObject = webClient.get() - .path("/greet") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello World!")); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello Joe!")); - - response = webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .await(); - assertThat(response.status().code(), is(204)); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hola Joe!")); - - response = webClient.get() - .path("/metrics") - .request() - .await(); - assertThat(response.status().code(), is(200)); - } - - @Test - public void testMetrics() { - WebClientResponse response; - - String get = webClient.get() - .path("/greet") - .request(String.class) - .await(); - - assertThat(get, containsString("Hello World!")); - - get = webClient.get() - .path("/greet/Joe") - .request(String.class) - .await(); - - assertThat(get, containsString("Hello Joe!")); - - String openMetricsOutput = webClient.get() - .path("/metrics/application") - .request(String.class) - .await(); - - assertThat("Metrics output", openMetricsOutput, not(containsString(GreetService.TIMER_FOR_GETS))); - assertThat("Metrics output", openMetricsOutput, containsString(GreetService.COUNTER_FOR_PERSONALIZED_GREETINGS)); - } -} diff --git a/examples/metrics/http-status-count-se/README.md b/examples/metrics/http-status-count-se/README.md deleted file mode 100644 index 6eff1943ef3..00000000000 --- a/examples/metrics/http-status-count-se/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# http-status-count-se - -This Helidon SE project illustrates a service which updates a family of counters based on the HTTP status returned in each response. - -The main source in this example is identical to that in the Helidon SE QuickStart application except in these ways: -* The `HttpStatusMetricService` class creates and updates the status metrics. -* The `Main` class has a two small enhancements: - * The `createRouting` method instantiates `HttpStatusMetricService` and sets up routing for it. - * The `startServer` method has an additional variant to simplify a new unit test. - -## Incorporating status metrics into your own application -Use this example for inspiration in writing your own service or just use the `HttpStatusMetricService` directly in your own application. - -1. Copy and paste the `HttpStatusMetricService` class into your application, adjusting the package declaration as needed. -2. Register routing for an instance of `HttpStatusMetricService`, as shown here: - ```java - Routing.Builder builder = Routing.builder() - ... - .register(HttpStatusMetricService.create() - ... - ``` - -## Build and run - - -With JDK17+ -```bash -mvn package -java -jar target/http-status-count-se.jar -``` - -## Exercise the application -```bash -curl -X GET http://localhost:8080/simple-greet -``` -```listing -{"message":"Hello World!"} -``` - -```bash -curl -X GET http://localhost:8080/greet -``` -```listing -{"message":"Hello World!"} -``` -```bash -curl -X GET http://localhost:8080/greet/Joe -``` -```listing -{"message":"Hello Joe!"} -``` -```bash -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -``` -```listing -{"message":"Hola Jose!"} -``` - -## Try metrics -```bash -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics/application -``` - -```listing -... -# TYPE application_httpStatus_total counter -# HELP application_httpStatus_total Counts the number of HTTP responses in each status category (1xx, 2xx, etc.) -application_httpStatus_total{range="1xx"} 0 -application_httpStatus_total{range="2xx"} 5 -application_httpStatus_total{range="3xx"} 0 -application_httpStatus_total{range="4xx"} 0 -application_httpStatus_total{range="5xx"} 0 -... -``` -# JSON Format - -```bash -curl -H "Accept: application/json" -X GET http://localhost:8080/metrics -``` -```json -{ -... - "httpStatus;range=1xx": 0, - "httpStatus;range=2xx": 5, - "httpStatus;range=3xx": 0, - "httpStatus;range=4xx": 0, - "httpStatus;range=5xx": 0, -... -``` - -## Try health - -```bash -curl -s -X GET http://localhost:8080/health -``` -```listing -{"outcome":"UP",... - -``` diff --git a/examples/metrics/http-status-count-se/pom.xml b/examples/metrics/http-status-count-se/pom.xml deleted file mode 100644 index 113fe35edad..00000000000 --- a/examples/metrics/http-status-count-se/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples - http-status-count-se - 1.0-SNAPSHOT - - Helidon Examples Metrics HTTP Status Counters - - - io.helidon.examples.se.httpstatuscount.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.metrics - helidon-metrics - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.media - helidon-media-jsonp - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java deleted file mode 100644 index 9e94b7ea7ec..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.se.httpstatuscount; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; - - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); - - GreetService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - } - - /** - * A service registers itself by updating the routing rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - if (ex.getCause() instanceof JsonException) { - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } -} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java deleted file mode 100644 index 4912112b4c5..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.se.httpstatuscount; - -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.Metadata; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.MetricType; -import org.eclipse.microprofile.metrics.MetricUnits; -import org.eclipse.microprofile.metrics.Tag; - -/** - * Helidon SE service to update a family of counters based on the HTTP status of each response. Add an instance of this service - * to the application's routing. - *

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

- */ -public class HttpStatusMetricService implements Service { - - static final String STATUS_COUNTER_NAME = "httpStatus"; - - static final String STATUS_TAG_NAME = "range"; - - private static final AtomicInteger IN_PROGRESS = new AtomicInteger(); - - private final Counter[] responseCounters = new Counter[6]; - - static HttpStatusMetricService create() { - return new HttpStatusMetricService(); - } - - private HttpStatusMetricService() { - MetricRegistry appRegistry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); - Metadata metadata = Metadata.builder() - .withName(STATUS_COUNTER_NAME) - .withDisplayName("HTTP response values") - .withDescription("Counts the number of HTTP responses in each status category (1xx, 2xx, etc.)") - .withType(MetricType.COUNTER) - .withUnit(MetricUnits.NONE) - .build(); - // Declare the counters and keep references to them. - for (int i = 1; i < responseCounters.length; i++) { - responseCounters[i] = appRegistry.counter(metadata, new Tag(STATUS_TAG_NAME, i + "xx")); - } - } - - @Override - public void update(Routing.Rules rules) { - rules.any(this::updateRange); - } - - // for testing - static boolean isInProgress() { - return IN_PROGRESS.get() != 0; - } - - // Edited to adopt Ciaran's fix later in the thread. - private void updateRange(ServerRequest request, ServerResponse response) { - IN_PROGRESS.incrementAndGet(); - response.whenSent() - .thenAccept(this::logMetric); - request.next(); - } - - private void logMetric(ServerResponse response) { - int range = response.status().code() / 100; - if (range > 0 && range < responseCounters.length) { - responseCounters[range].inc(); - } - IN_PROGRESS.decrementAndGet(); - } -} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java deleted file mode 100644 index 2137d1a2bae..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.se.httpstatuscount; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - return startServer(createRouting(Config.create())); - } - - static Single startServer(Routing.Builder routingBuilder) { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(routingBuilder) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - static Routing.Builder createRouting(Config config) { - SimpleGreetService simpleGreetService = new SimpleGreetService(config); - GreetService greetService = new GreetService(config); - - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - Routing.Builder builder = Routing.builder() - .register(MetricsSupport.create()) // Metrics at "/metrics" - .register(health) // Health at "/health" - .register(HttpStatusMetricService.create()) // no endpoint, just metrics updates - .register("/simple-greet", simpleGreetService) - .register("/greet", greetService); - - - return builder; - } -} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java deleted file mode 100644 index 2d9508ab7e3..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.se.httpstatuscount; - -import java.util.Collections; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricRegistry; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/simple-greet - * - * The message is returned as a JSON object - */ -public class SimpleGreetService implements Service { - - private static final Logger LOGGER = Logger.getLogger(SimpleGreetService.class.getName()); - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private final MetricRegistry registry = RegistryFactory.getInstance() - .getRegistry(MetricRegistry.Type.APPLICATION); - private final Counter accessCtr = registry.counter("accessctr"); - - private final String greeting; - - SimpleGreetService(Config config) { - greeting = config.get("app.greeting").asString().orElse("Ciao"); - } - - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules.get("/", this::getDefaultMessageHandler); - rules.get("/greet-count", this::countAccess, this::getDefaultMessageHandler); - } - - /** - * Return a worldly greeting message. - * - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { - String msg = String.format("%s %s!", greeting, "World"); - LOGGER.info("Greeting message is " + msg); - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - - private void countAccess(ServerRequest request, ServerResponse response) { - accessCtr.inc(); - request.next(); - } -} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java deleted file mode 100644 index d5b622ea310..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * HTTP status count example. - */ -package io.helidon.examples.se.httpstatuscount; diff --git a/examples/metrics/http-status-count-se/src/main/resources/application.yaml b/examples/metrics/http-status-count-se/src/main/resources/application.yaml deleted file mode 100644 index e1e6249d8d4..00000000000 --- a/examples/metrics/http-status-count-se/src/main/resources/application.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 8080 - host: 0.0.0.0 - -app: - greeting: "Hello" - - diff --git a/examples/metrics/http-status-count-se/src/main/resources/logging.properties b/examples/metrics/http-status-count-se/src/main/resources/logging.properties deleted file mode 100644 index d73eb5b6607..00000000000 --- a/examples/metrics/http-status-count-se/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java deleted file mode 100644 index a8dfdf64d0f..00000000000 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.se.httpstatuscount; - -import java.util.concurrent.TimeUnit; -import java.util.Collections; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -@TestMethodOrder(MethodOrderer.MethodName.class) -public class MainTest { - - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - - private static WebServer webServer; - private static WebClient webClient; - - @BeforeAll - public static void startTheServer() { - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - public static void stopServer() throws Exception { - if (webServer != null) { - webServer.shutdown() - .toCompletableFuture() - .get(10, TimeUnit.SECONDS); - } - } - - - @Test - public void testMicroprofileMetrics() { - String get = webClient.get() - .path("/simple-greet/greet-count") - .request(String.class) - .await(); - - assertThat(get, containsString("Hello World!")); - - String openMetricsOutput = webClient.get() - .path("/metrics") - .request(String.class) - .await(); - - assertThat("Metrics output", openMetricsOutput, containsString("application_accessctr_total")); - } - - @Test - public void testMetrics() throws Exception { - WebClientResponse response = webClient.get() - .path("/metrics") - .request() - .await(); - assertThat(response.status().code(), is(200)); - } - - @Test - public void testHealth() throws Exception { - WebClientResponse response = webClient.get() - .path("health") - .request() - .await(); - assertThat(response.status().code(), is(200)); - } - - @Test - public void testSimpleGreet() throws Exception { - JsonObject jsonObject = webClient.get() - .path("/simple-greet") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello World!")); - } - @Test - public void testGreetings() { - JsonObject jsonObject; - WebClientResponse response; - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello Joe!")); - - response = webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .await(); - assertThat(response.status().code(), is(204)); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hola Joe!")); - } -} diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java deleted file mode 100644 index 68816a3c0b6..00000000000 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.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.examples.se.httpstatuscount; - -import io.helidon.common.http.Http; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * Test-only service that allows the client to specify what HTTP status the service should return in its response. - * This allows the client to know which status family counter should be updated. - */ -public class StatusService implements Service { - - @Override - public void update(Routing.Rules rules) { - rules.get("/{status}", this::respondWithRequestedStatus); - } - - private void respondWithRequestedStatus(ServerRequest request, ServerResponse response) { - String statusText = request.path().param("status"); - int status; - String msg; - try { - status = Integer.parseInt(statusText); - msg = "Successful conversion"; - } catch (NumberFormatException ex) { - status = Http.Status.INTERNAL_SERVER_ERROR_500.code(); - msg = "Unsuccessful conversion"; - } - response.status(status) - .send(msg); - } -} diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java deleted file mode 100644 index ab6ab1c4ee2..00000000000 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.se.httpstatuscount; - -import java.time.Duration; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http.ResponseStatus; -import io.helidon.common.http.Http.Status; -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricID; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Tag; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isEmptyString; -import static org.junit.jupiter.api.Assertions.fail; - -public class StatusTest { - private static final Duration TIMEOUT = Duration.ofSeconds(10); - - private static WebServer webServer; - private static WebClient webClient; - - private final Counter[] STATUS_COUNTERS = new Counter[6]; - - @AfterAll - public static void stopServer() throws Exception { - if (webServer != null) { - webServer.shutdown() - .toCompletableFuture() - .get(10, TimeUnit.SECONDS); - } - } - - @BeforeAll - static void init() { - Routing.Builder routingBuilder = Main.createRouting(Config.create()); - routingBuilder.register("/status", new StatusService()); - - webServer = Main.startServer(routingBuilder).await(TIMEOUT); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @BeforeEach - void findStatusMetrics() { - MetricRegistry metricRegistry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); - for (int i = 1; i < STATUS_COUNTERS.length; i++) { - STATUS_COUNTERS[i] = metricRegistry.counter(new MetricID(HttpStatusMetricService.STATUS_COUNTER_NAME, - new Tag(HttpStatusMetricService.STATUS_TAG_NAME, i + "xx"))); - } - } - - @Test - void checkStatusMetrics() throws ExecutionException, InterruptedException { - checkAfterStatus(ResponseStatus.create(171)); - checkAfterStatus(Status.OK_200); - checkAfterStatus(Status.CREATED_201); - checkAfterStatus(Status.NO_CONTENT_204); - checkAfterStatus(Status.MOVED_PERMANENTLY_301); - checkAfterStatus(Status.UNAUTHORIZED_401); - checkAfterStatus(Status.NOT_FOUND_404); - } - - @Test - void checkStatusAfterGreet() throws ExecutionException, InterruptedException { - long[] before = new long[6]; - for (int i = 1; i < 6; i++) { - before[i] = STATUS_COUNTERS[i].getCount(); - } - WebClientResponse response = webClient.get() - .path("/greet") - .accept(MediaType.APPLICATION_JSON) - .request() - .get(); - assertThat("Status of /greet", response.status(), is(Status.OK_200)); - String entity = response.content().as(String.class).await(TIMEOUT); - assertThat(entity, not(isEmptyString())); - checkCounters(response.status(), before); - } - - void checkAfterStatus(ResponseStatus status) throws ExecutionException, InterruptedException { - long[] before = new long[6]; - for (int i = 1; i < 6; i++) { - before[i] = STATUS_COUNTERS[i].getCount(); - } - WebClientResponse response = webClient.get() - .path("/status/" + status.code()) - .accept(MediaType.APPLICATION_JSON) - .request() - .get(); - - assertThat("Response status", response.status().code(), is(status.code())); - String entity = response.content().as(String.class).await(TIMEOUT); - - checkCounters(status, before); - } - - private void checkCounters(ResponseStatus status, long[] before) throws InterruptedException { - // first make sure we do not have a request in progress - long now = System.currentTimeMillis(); - - while (HttpStatusMetricService.isInProgress()) { - Thread.sleep(50); - if (System.currentTimeMillis() - now > 5000) { - fail("Timed out while waiting for monitoring to finish"); - } - } - - int family = status.code() / 100; - for (int i = 1; i < 6; i++) { - long expectedDiff = i == family ? 1 : 0; - assertThat("Diff in counter " + family + "xx", STATUS_COUNTERS[i].getCount() - before[i], is(expectedDiff)); - } - } -} diff --git a/examples/metrics/http-status-count-se/src/test/resources/application.yaml b/examples/metrics/http-status-count-se/src/test/resources/application.yaml deleted file mode 100644 index b9f100a8492..00000000000 --- a/examples/metrics/http-status-count-se/src/test/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 0 - host: 0.0.0.0 - -app: - greeting: "Hello" - -security: - enabled: false - diff --git a/examples/metrics/kpi/README.md b/examples/metrics/kpi/README.md deleted file mode 100644 index 8daaf3b1c1d..00000000000 --- a/examples/metrics/kpi/README.md +++ /dev/null @@ -1,122 +0,0 @@ -# Helidon Metrics Key Performance Indicators SE Example - -This project implements a simple Hello World REST service using Helidon SE and demonstrates -support in Helidon for extended key performance indicator (KPI) metrics. - -Your application can set up KPI metrics either programmatically or using configuration. -The `Main` class of this example shows both techniques, checking the system property `useConfig` to -determine -which to use. -You would typically write any given application to use only one of the approaches. - -## Build and run - -With JDK11+ -```bash -mvn package -``` -To use programmatic set-up: -```bash -java -jar target/helidon-examples-metrics-kpi.jar -``` -To use configuration: -```bash -java -DuseConfig=true -jar target/helidon-examples-metrics-kpi.jar -```` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/greet -{"message":"Hola World!"} -``` - -## Retrieve vendor metrics with key performance indicators - -For brevity, the example output below shows only some of the KPI metrics. - -Note that, even though the `curl` commands above access `/greet` endpoints five times, -the -`load` and (not shown here) -`count` and -`meter` are `6` in the Prometheus output example and `7` in the JSON output example. -Further, the `inFlight` -current value is `1`. - -This is -because Helidon tallies -all -requests, even those -to Helidon-provided services such as `/metrics` and `/health`, in the KPI metrics. -The request -to retrieve the metrics is the one that is in flight, and it contributes to the KPI metrics just -as requests to application endpoints do. - -Further, the request to `/metrics` is still in progress when Helidon prepares the -output by getting the values of the KPI metrics at that moment. -If _that_ request turns out to be long- running, Helidon would discover so only -_after_ preparing the metrics output and completing the request. -The `longRunning` `Meter` -values in _that_ -response -could -not reflect the fact that Helidon would subsequently conclude that _that_ request was -long-running. - -## Prometheus format -``` -curl -s -X GET http://localhost:8080/metrics/vendor -... -# TYPE vendor_requests_inFlight_current concurrent gauge -# HELP vendor_requests_inFlight_current Measures the number of currently in-flight requests -vendor_requests_inFlight_current 1 -# TYPE vendor_requests_inFlight_min concurrent gauge -vendor_requests_inFlight_min 0 -# TYPE vendor_requests_inFlight_max concurrent gauge -vendor_requests_inFlight_max 1 -# TYPE vendor_requests_load_total counter -# HELP vendor_requests_load_total Measures the total number of in-flight requests and rates at which they occur -vendor_requests_load_total 6 -# TYPE vendor_requests_load_rate_per_second gauge -vendor_requests_load_rate_per_second 0.04932913209653636 -# TYPE vendor_requests_load_one_min_rate_per_second gauge -vendor_requests_load_one_min_rate_per_second 0.025499793037824785 -# TYPE vendor_requests_load_five_min_rate_per_second gauge -vendor_requests_load_five_min_rate_per_second 0.012963147773962286 -# TYPE vendor_requests_load_fifteen_min_rate_per_second gauge -vendor_requests_load_fifteen_min_rate_per_second 0.005104944851522425 -... -``` -## JSON output - - -```bash -curl -s -X GET -H "Accept: application/json" http://localhost:8080/metrics/vendor -{ - ... - "requests.inFlight": { - "current": 1, - "max": 1, - "min": 0 - }, - "requests.load": { - "count": 7, - "meanRate": 0.01530869471741443, - "oneMinRate": 0.00016123154886115814, - "fiveMinRate": 0.005344110443653005, - "fifteenMinRate": 0.004286243527303867 - }, - ... -} -``` diff --git a/examples/metrics/kpi/pom.xml b/examples/metrics/kpi/pom.xml deleted file mode 100644 index 07d6a8004b3..00000000000 --- a/examples/metrics/kpi/pom.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - 4.0.0 - - io.helidon.examples.metrics - helidon-examples-metrics-kpi - Helidon Examples Metrics Key Performance Indicators - - io.helidon.examples.metrics.kpi.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - io.helidon.config - helidon-config-yaml - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - check-for-inflight-with-config-settings - - test - - - - true - - - - - - - - diff --git a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/GreetService.java b/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/GreetService.java deleted file mode 100644 index 637326b939a..00000000000 --- a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/GreetService.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.metrics.kpi; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.Metadata; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.MetricType; -import org.eclipse.microprofile.metrics.MetricUnits; -import org.eclipse.microprofile.metrics.Timer; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); - - static final String TIMER_FOR_GETS = "timerForGets"; - static final String COUNTER_FOR_PERSONALIZED_GREETINGS = "counterForPersonalizedGreetings"; - - private final Timer timerForGets; - - private final Counter personalizedGreetingsCounter; - - private final Config config; - - GreetService(Config config) { - this.config = config; - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - MetricRegistry registry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); - Metadata metadata = Metadata.builder() - .withName(TIMER_FOR_GETS) - .withUnit(MetricUnits.NANOSECONDS) - .withType(MetricType.TIMER) - .build(); - timerForGets = registry.timer(metadata); - - metadata = Metadata.builder() - .withName(COUNTER_FOR_PERSONALIZED_GREETINGS) - .withUnit(MetricUnits.NONE) - .withType(MetricType.COUNTER) - .build(); - personalizedGreetingsCounter = registry.counter(metadata); - } - - /** - * A service registers itself by updating the routing rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::timeGet, this::getDefaultMessageHandler) - .get("/{name}", this::countPersonalized, this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - if (ex.getCause() instanceof JsonException){ - - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } - - private void timeGet(ServerRequest request, ServerResponse response) { - timerForGets.time((Runnable) request::next); - } - - private void countPersonalized(ServerRequest request, ServerResponse response) { - personalizedGreetingsCounter.inc(); - request.next(); - } -} diff --git a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/Main.java b/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/Main.java deleted file mode 100644 index 48a3d1d01ca..00000000000 --- a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/Main.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.metrics.kpi; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.api.KeyPerformanceIndicatorMetricsSettings; -import io.helidon.metrics.api.MetricsSettings; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class Main { - - static final String USE_CONFIG_PROPERTY_NAME = "useConfig"; - - static final boolean USE_CONFIG = Boolean.getBoolean(USE_CONFIG_PROPERTY_NAME); - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder() - .routing(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - /* - * For purposes of illustration, the key performance indicator settings for the - * MetricsSupport instance are set up according to a system property so you can see, - * in one example, how to code each approach. Normally, you would choose one - * approach to use in an application. - */ - MetricsSupport metricsSupport = USE_CONFIG - ? metricsSupportWithConfig(config.get("metrics")) - : metricsSupportWithoutConfig(); - - GreetService greetService = new GreetService(config); - - return Routing.builder() - .register(metricsSupport) // Metrics at "/metrics" - .register("/greet", greetService) - .build(); - } - - /** - * Creates a {@link MetricsSupport} instance using a "metrics" configuration node. - * - * @param metricsConfig {@link Config} node with key "metrics" if present; an empty node otherwise - * @return {@code MetricsSupport} object with metrics (including KPI) set up using the config node - */ - private static MetricsSupport metricsSupportWithConfig(Config metricsConfig) { - return MetricsSupport.create(metricsConfig); - } - - /** - * Creates a {@link MetricsSupport} instance explicitly turning on extended KPI metrics. - * - * @return {@code MetricsSupport} object with extended KPI metrics enabled - */ - private static MetricsSupport metricsSupportWithoutConfig() { - - KeyPerformanceIndicatorMetricsSettings.Builder settingsBuilder = - KeyPerformanceIndicatorMetricsSettings.builder() - .extended(true) - .longRunningRequestThresholdMs(2000); - return MetricsSupport.builder() - .metricsSettings(MetricsSettings.builder() - .keyPerformanceIndicatorSettings(settingsBuilder)) - .build(); - } -} diff --git a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/package-info.java b/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/package-info.java deleted file mode 100644 index 04a9b466633..00000000000 --- a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quickstart demo application for key performance metrics. - *

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

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

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

-

- \ No newline at end of file diff --git a/examples/microprofile/hello-world-explicit/README.md b/examples/microprofile/hello-world-explicit/README.md deleted file mode 100644 index 837350fe6b2..00000000000 --- a/examples/microprofile/hello-world-explicit/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Helidon MP Hello World Explicit Example - -This examples shows a simple application written using Helidon MP. -It is explicit because in this example you write the `main` class -and explicitly start the microprofile server. - -```bash -mvn package -java -jar target/helidon-examples-microprofile-hello-world-explicit.jar -``` - -Then try the endpoints: - -``` -curl -X GET http://localhost:7001/helloworld -curl -X GET http://localhost:7001/helloworld/earth -``` - -By default the server will use a dynamic port, see the messages displayed -when the application starts. diff --git a/examples/microprofile/hello-world-explicit/pom.xml b/examples/microprofile/hello-world-explicit/pom.xml deleted file mode 100644 index d1df553c560..00000000000 --- a/examples/microprofile/hello-world-explicit/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - helidon-examples-microprofile-hello-world-explicit - Helidon Microprofile Examples Explicit Hello World - - - Microprofile example with explicit bootstrapping (Server.create(Application.class).start()) - - - - io.helidon.microprofile.example.helloworld.explicit.Main - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/HelloWorldResource.java b/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/HelloWorldResource.java deleted file mode 100644 index ec6b03bfe95..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/HelloWorldResource.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.explicit; - -import java.net.URI; -import java.util.Collections; - -import io.helidon.config.Config; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.enterprise.inject.spi.BeanManager; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Example resource. - */ -@Path("helloworld") -@RequestScoped -public class HelloWorldResource { - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - private final Config config; - private final String applicationName; - private final URI applicationUri; - private BeanManager beanManager; - - /** - * Constructor injection of field values. - * - * @param config configuration instance - * @param appName name of application from config (app.name) - * @param appUri URI of application from config (app.uri) - * @param beanManager bean manager (injected automatically by CDI) - */ - @Inject - public HelloWorldResource(Config config, - @ConfigProperty(name = "app.name") String appName, - @ConfigProperty(name = "app.uri") URI appUri, - BeanManager beanManager) { - this.config = config; - this.applicationName = appName; - this.applicationUri = appUri; - this.beanManager = beanManager; - } - - /** - * Hello world GET method. - * - * @return string with application name - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String message() { - return "Hello World from application " + applicationName; - } - - /** - * Hello World GET method returning JSON. - * - * @param name name to add to response - * @return JSON with name and configured fields of this class - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject getHello(@PathParam("name") String name) { - return JSON.createObjectBuilder() - .add("name", name) - .add("appName", applicationName) - .add("appUri", String.valueOf(applicationUri)) - .add("config", config.get("my.property").asString().get()) - .add("beanManager", beanManager.toString()) - .build(); - } -} diff --git a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/Main.java b/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/Main.java deleted file mode 100644 index fe420cf14a7..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/Main.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.explicit; - -import io.helidon.microprofile.server.Server; - -/** - * Explicit example. - */ -public class Main { - private Main() { - } - - /** - * Starts server manually. - * - * @param args command line arguments (ignored) - */ - public static void main(String[] args) { - Server server = Server.builder() - .host("localhost") - // use a random free port - .port(0) - .build(); - - server.start(); - - String endpoint = "http://" + server.host() + ":" + server.port(); - System.out.println("Started application on " + endpoint + "/helloworld"); - System.out.println("Metrics available on " + endpoint + "/metrics"); - System.out.println("Heatlh checks available on " + endpoint + "/health"); - - } -} diff --git a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/package-info.java b/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/package-info.java deleted file mode 100644 index d170a0bfe83..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Explicit example (configures server and resources). - */ -package io.helidon.microprofile.example.helloworld.explicit; diff --git a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/beans.xml b/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 0a58d35be73..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app.name=Hello World Application -app.uri=https://www.example.com - -my.property=propertyValue - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/microprofile/hello-world-explicit/src/main/resources/logging.properties b/examples/microprofile/hello-world-explicit/src/main/resources/logging.properties deleted file mode 100644 index 0615cfef72c..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/resources/logging.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler - -io.helidon.common.HelidonConsoleHandler.level=ALL -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#All log level details -.level=WARNING -io.helidon.level=INFO diff --git a/examples/microprofile/hello-world-implicit/README.md b/examples/microprofile/hello-world-implicit/README.md deleted file mode 100644 index 393607f09da..00000000000 --- a/examples/microprofile/hello-world-implicit/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Helidon MP Hello World Implicit Example - -This examples shows a simple application written using Helidon MP. -It is implicit because in this example you don't write the -`main` class, instead you rely on the Microprofile Server main class. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-microprofile-hello-world-implicit.jar -``` - -Then try the endpoints: - -``` -curl -X GET http://localhost:7001/helloworld -curl -X GET http://localhost:7001/helloworld/earth -curl -X GET http://localhost:7001/another -``` diff --git a/examples/microprofile/hello-world-implicit/pom.xml b/examples/microprofile/hello-world-implicit/pom.xml deleted file mode 100644 index fb8b57efb1f..00000000000 --- a/examples/microprofile/hello-world-implicit/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-hello-world-implicit - Helidon Microprofile Examples Implicit Hello World - - - Microprofile example with implicit bootstrapping (cdi.Main(new String[0]) - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.jboss - jandex - runtime - true - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java deleted file mode 100644 index 11a8b6d6281..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.implicit; - -import java.net.URI; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Resource showing all possible configuration injections. - */ -@Path("another") -@RequestScoped -public class AnotherResource { - @Inject - @ConfigProperty(name = "app.nonExistent", defaultValue = "145") - private int defaultValue; - - @Inject - @ConfigProperty(name = "app.nonExistent") - private Optional empty; - - @Inject - @ConfigProperty(name = "app.uri") - private Optional full; - - @Inject - @ConfigProperty(name = "app.someInt") - private Provider provider; - - @Inject - @ConfigProperty(name = "app.ints") - private List ints; - - @Inject - @ConfigProperty(name = "app.ints") - private Optional> optionalInts; - - @Inject - @ConfigProperty(name = "app.ints") - private Provider> providedInts; - - @Inject - @ConfigProperty(name = "app.ints") - private int[] intsArray; - - @Inject - @ConfigProperty(name = "app") - private Map detached; - - @Inject - private Config mpConfig; - - @Inject - private io.helidon.config.Config helidonConfig; - - /** - * Get method to validate that all injections worked. - * - * @return data from all fields of this class - */ - @GET - public String get() { - return toString(); - } - - @Override - public String toString() { - return "AnotherResource{" - + "defaultValue=" + defaultValue - + ", empty=" + empty - + ", full=" + full - + ", provider=" + provider + "(" + provider.get() + ")" - + ", ints=" + ints - + ", optionalInts=" + optionalInts - + ", providedInts=" + providedInts + "(" + providedInts.get() + ")" - + ", detached=" + detached - + ", microprofileConfig=" + mpConfig - + ", helidonConfig=" + helidonConfig - + ", intsArray=" + Arrays.toString(intsArray) - + '}'; - } -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java deleted file mode 100644 index 4fe49e4ca08..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.implicit; - -import java.net.URI; -import java.util.Collections; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.microprofile.example.helloworld.implicit.cdi.LoggerQualifier; -import io.helidon.microprofile.example.helloworld.implicit.cdi.RequestId; -import io.helidon.microprofile.example.helloworld.implicit.cdi.ResourceProducer; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.enterprise.inject.spi.BeanManager; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Resource for hello world example. - */ -@Path("helloworld") -@RequestScoped -public class HelloWorldResource { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private final Config config; - private final Logger logger; - private final int requestId; - private final String applicationName; - private final URI applicationUri; - private BeanManager beanManager; - - /** - * Using constructor injection for field values. - * - * @param config configuration instance - * @param logger logger (from {@link ResourceProducer} - * @param requestId requestId (from {@link ResourceProducer} - * @param appName name from configuration (app.name) - * @param appUri URI from configuration (app.uri) - * @param beanManager bean manager (injected automatically by CDI) - */ - @Inject - public HelloWorldResource(Config config, - @LoggerQualifier Logger logger, - @RequestId int requestId, - @ConfigProperty(name = "app.name") String appName, - @ConfigProperty(name = "app.uri") URI appUri, - BeanManager beanManager) { - this.config = config; - this.logger = logger; - this.requestId = requestId; - this.applicationName = appName; - this.applicationUri = appUri; - this.beanManager = beanManager; - } - - /** - * Get method for this resource, shows logger and request id. - * - * @return hello world - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String message() { - return "Hello World: " + logger + ", request: " + requestId + ", appName: " + applicationName; - } - - /** - * Get method for this resource, returning JSON. - * - * @param name name to add to response - * @return JSON structure with injected fields - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject getHello(@PathParam("name") String name) { - return JSON.createObjectBuilder() - .add("name", name) - .add("requestId", requestId) - .add("appName", applicationName) - .add("appUri", String.valueOf(applicationUri)) - .add("config", config.get("server.port").asInt().get()) - .add("beanManager", beanManager.toString()) - .add("logger", logger.getName()) - .build(); - } -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java deleted file mode 100644 index 7de3e86dbb7..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.implicit.cdi; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Use this qualifier to inject logger instances. - */ -@Qualifier -@Retention(RUNTIME) -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) -public @interface LoggerQualifier { -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java deleted file mode 100644 index c4e904e6c5e..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.implicit.cdi; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -/** - * Request id qualifier to inject increasing request id. - */ -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) -public @interface RequestId { -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java deleted file mode 100644 index 2eacb8ff66d..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.implicit.cdi; - -import jakarta.enterprise.context.ApplicationScoped; - -/** - * Produce an ever increasing request id. - */ -@ApplicationScoped -public class RequestIdProducer { - -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java deleted file mode 100644 index 206be30fb38..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.implicit.cdi; - -import java.util.concurrent.atomic.AtomicInteger; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.enterprise.inject.spi.InjectionPoint; - -/** - * Producer for various resources required by this example. - */ -@ApplicationScoped -public class ResourceProducer { - private static final AtomicInteger COUNTER = new AtomicInteger(); - - /** - * Each injection will increase the COUNTER. - * - * @return increased COUNTER value - */ - @Produces - @RequestId - public int produceRequestId() { - return COUNTER.incrementAndGet(); - } - - /** - * Create/get a logger instance for the class that the logger is being injected into. - * - * @param injectionPoint injection point - * @return a logger instance - */ - @Produces - @LoggerQualifier - public java.util.logging.Logger produceLogger(final InjectionPoint injectionPoint) { - return java.util.logging.Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); - } -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java deleted file mode 100644 index 3de41659971..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * CDI classes for example. - */ -package io.helidon.microprofile.example.helloworld.implicit.cdi; diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java deleted file mode 100644 index 19d08407637..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Implicit HelloWorld example (starts server without configuration). - */ -package io.helidon.microprofile.example.helloworld.implicit; diff --git a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/beans.xml b/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index bbae60a1ba5..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app.name=Hello World Application -app.someInt=147 -app.uri=https://www.example.com -app.someInt=147 -app.ints=12,12,32,12,44 - -server.port=7001 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/microprofile/hello-world-implicit/src/main/resources/logging.properties b/examples/microprofile/hello-world-implicit/src/main/resources/logging.properties deleted file mode 100644 index 7b0371c8484..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.config.level=FINEST diff --git a/examples/microprofile/hello-world-implicit/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java b/examples/microprofile/hello-world-implicit/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java deleted file mode 100644 index e6cc1e9b229..00000000000 --- a/examples/microprofile/hello-world-implicit/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.helloworld.implicit; - -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.WebTarget; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertAll; - -/** - * Unit test for {@link HelloWorldResource}. - */ -@HelidonTest -class ImplicitHelloWorldTest { - private final WebTarget target; - - @Inject - ImplicitHelloWorldTest(WebTarget target) { - this.target = target; - } - @Test - void testJsonResource() { - JsonObject jsonObject = target - .path("/helloworld/unit") - .request() - .get(JsonObject.class); - - assertAll("JSON fields must match expected injection values", - () -> assertThat("Name from request", jsonObject.getString("name"), is("unit")), - () -> assertThat("Request id from CDI provider", jsonObject.getInt("requestId"), is(1)), - () -> assertThat("App name from config", jsonObject.getString("appName"), is("Hello World Application")), - () -> assertThat("Logger name", jsonObject.getString("logger"), is(HelloWorldResource.class.getName())) - ); - - } -} diff --git a/examples/microprofile/http-status-count-mp/README.md b/examples/microprofile/http-status-count-mp/README.md deleted file mode 100644 index 0e574905de9..00000000000 --- a/examples/microprofile/http-status-count-mp/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# http-status-count-mp - -This Helidon MP project illustrates a filter which updates a family of counters based on the HTTP status returned in each response. - -The addition of the single filter class `HttpStatusMetricFilter` is the only difference from the Helidon MP QuickStart project. - -## Incorporating status metrics into your own application -Use this example for inspiration in writing your own filter or just use the filter directly in your own application by copying and pasting the `HttpStatusMetricFilter` class into your application, adjusting the package declaration as needed. Helidon MP discovers and uses your filter automatically. - -## Build and run - - -With JDK17+ -```bash -mvn package -java -jar target/http-status-count-mp.jar -``` - -## Exercise the application -```bash -curl -X GET http://localhost:8080/simple-greet -``` -```listing -{"message":"Hello World!"} -``` - -```bash -curl -X GET http://localhost:8080/greet -``` -```listing -{"message":"Hello World!"} -``` -```bash -curl -X GET http://localhost:8080/greet/Joe -``` -```listing -{"message":"Hello Joe!"} -``` -```bash -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -``` -```listing -{"message":"Hola Jose!"} -``` - -## Try metrics -```bash -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics/application -``` - -```listing -... -# TYPE application_httpStatus_total counter -# HELP application_httpStatus_total Counts the number of HTTP responses in each status category (1xx, 2xx, etc.) -application_httpStatus_total{range="1xx"} 0 -application_httpStatus_total{range="2xx"} 5 -application_httpStatus_total{range="3xx"} 0 -application_httpStatus_total{range="4xx"} 0 -application_httpStatus_total{range="5xx"} 0 -... -``` -# JSON Format - -```bash -curl -H "Accept: application/json" -X GET http://localhost:8080/metrics -``` -```json -{ -... - "httpStatus;range=1xx": 0, - "httpStatus;range=2xx": 5, - "httpStatus;range=3xx": 0, - "httpStatus;range=4xx": 0, - "httpStatus;range=5xx": 0, -... diff --git a/examples/microprofile/http-status-count-mp/app.yaml b/examples/microprofile/http-status-count-mp/app.yaml deleted file mode 100644 index c893d52ddac..00000000000 --- a/examples/microprofile/http-status-count-mp/app.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: http-status-count-mp - labels: - app: http-status-count-mp -spec: - type: NodePort - selector: - app: http-status-count-mp - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - diff --git a/examples/microprofile/http-status-count-mp/pom.xml b/examples/microprofile/http-status-count-mp/pom.xml deleted file mode 100644 index 57c64f15ee0..00000000000 --- a/examples/microprofile/http-status-count-mp/pom.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples - http-status-count-mp - 1.0-SNAPSHOT - - Helidon Examples Metrics HTTP Status Counters - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.eclipse.microprofile.metrics - microprofile-metrics-api - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.microprofile.health - helidon-microprofile-health - - - org.jboss - jandex - runtime - - - jakarta.activation - jakarta.activation-api - runtime - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - io.helidon.webclient - helidon-webclient - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java deleted file mode 100644 index 5bcda14742f..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; - -/** - * A simple JAX-RS resource to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object. - */ -@Path("/greet") -@RequestScoped -public class GreetResource { - - /** - * The greeting message provider. - */ - private final GreetingProvider greetingProvider; - - /** - * Using constructor injection to get a configuration property. - * By default this gets the value from META-INF/microprofile-config - * - * @param greetingConfig the configured greeting message - */ - @Inject - public GreetResource(GreetingProvider greetingConfig) { - this.greetingProvider = greetingConfig; - } - - /** - * Return a worldly greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RequestBody(name = "greeting", - required = true, - content = @Content(mediaType = "application/json", - schema = @Schema(type = SchemaType.OBJECT, requiredProperties = { "greeting" }))) - @APIResponses({ - @APIResponse(name = "normal", responseCode = "204", description = "Greeting updated"), - @APIResponse(name = "missing 'greeting'", responseCode = "400", - description = "JSON did not contain setting for 'greeting'")}) - public Response updateGreeting(GreetingMessage message) { - - if (message.getMessage() == null) { - GreetingMessage error = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(error).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingMessage.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingMessage.java deleted file mode 100644 index d30fc5dc71d..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingMessage.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -/** - * Greeting message. - */ -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java deleted file mode 100644 index 95377db2797..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -import java.util.concurrent.atomic.AtomicReference; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Provider for greeting message. - */ -@ApplicationScoped -public class GreetingProvider { - private final AtomicReference message = new AtomicReference<>(); - - /** - * Create a new greeting provider, reading the message from configuration. - * - * @param message greeting to use - */ - @Inject - public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) { - this.message.set(message); - } - - String getMessage() { - return message.get(); - } - - void setMessage(String message) { - this.message.set(message); - } -} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java deleted file mode 100644 index 7117099095a..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -import java.io.IOException; - -import jakarta.annotation.PostConstruct; -import jakarta.inject.Inject; -import jakarta.ws.rs.ConstrainedTo; -import jakarta.ws.rs.RuntimeType; -import jakarta.ws.rs.container.ContainerRequestContext; -import jakarta.ws.rs.container.ContainerResponseContext; -import jakarta.ws.rs.container.ContainerResponseFilter; -import jakarta.ws.rs.ext.Provider; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.Metadata; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.MetricType; -import org.eclipse.microprofile.metrics.MetricUnits; -import org.eclipse.microprofile.metrics.Tag; - -/** - * REST service filter to update a family of counters based on the HTTP status of each response. - *

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

- */ -@ConstrainedTo(RuntimeType.SERVER) -@Provider -public class HttpStatusMetricFilter implements ContainerResponseFilter { - - static final String STATUS_COUNTER_NAME = "httpStatus"; - static final String STATUS_TAG_NAME = "range"; - - @Inject - private MetricRegistry metricRegistry; - - private final Counter[] responseCounters = new Counter[6]; - - @PostConstruct - private void init() { - Metadata metadata = Metadata.builder() - .withName(STATUS_COUNTER_NAME) - .withDisplayName("HTTP response values") - .withDescription("Counts the number of HTTP responses in each status category (1xx, 2xx, etc.)") - .withType(MetricType.COUNTER) - .withUnit(MetricUnits.NONE) - .build(); - // Declare the counters and keep references to them. - for (int i = 1; i < responseCounters.length; i++) { - responseCounters[i] = metricRegistry.counter(metadata, new Tag(STATUS_TAG_NAME, i + "xx")); - } - } - - @Override - public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) - throws IOException { - updateCountForStatus(containerResponseContext.getStatus()); - } - - private void updateCountForStatus(int statusCode) { - int range = statusCode / 100; - if (range > 0 && range < responseCounters.length) { - responseCounters[range].inc(); - } - } -} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java deleted file mode 100644 index 7516812b1ed..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.eclipse.microprofile.metrics.MetricUnits; -import org.eclipse.microprofile.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.Timed; - -/** - * A simple JAX-RS resource to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/simple-greet - * - * The message is returned as a JSON object. - */ -@Path("/simple-greet") -public class SimpleGreetResource { - - private static final String PERSONALIZED_GETS_COUNTER_NAME = "personalizedGets"; - private static final String PERSONALIZED_GETS_COUNTER_DESCRIPTION = "Counts personalized GET operations"; - private static final String GETS_TIMER_NAME = "allGets"; - private static final String GETS_TIMER_DESCRIPTION = "Tracks all GET operations"; - private final String message; - - /** - * Creates a new instance using the configured default greeting. - * @param message initial greeting message - */ - @Inject - public SimpleGreetResource(@ConfigProperty(name = "app.greeting") String message) { - this.message = message; - } - - /** - * Return a worldly greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - String msg = String.format("%s %s!", message, "World"); - GreetingMessage message = new GreetingMessage(); - message.setMessage(msg); - return message; - } - - /** - * Returns a personalized greeting. - * - * @param name name with which to personalize the greeting - * @return personalized greeting message - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - @Counted(name = PERSONALIZED_GETS_COUNTER_NAME, - absolute = true, - description = PERSONALIZED_GETS_COUNTER_DESCRIPTION) - @Timed(name = GETS_TIMER_NAME, - description = GETS_TIMER_DESCRIPTION, - unit = MetricUnits.SECONDS, - absolute = true) - public String getMessage(@PathParam("name") String name) { - return String.format("Hello %s", name); - } - -} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java deleted file mode 100644 index 11bfe9067aa..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * HTTP status count example. - */ -package io.helidon.examples.mp.httpstatuscount; diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 754aa3ed1d8..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index affefe0a610..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2022, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Change the following to true to enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=false - -# Application properties. This is the default greeting -app.greeting=Hello - - diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json deleted file mode 100644 index fe51488c706..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml b/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml deleted file mode 100644 index 3a5ab924b72..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -server.port: 8080 diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties b/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties deleted file mode 100644 index ae74a159f9c..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2022, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Quiet Weld -org.jboss.level=WARNING - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java deleted file mode 100644 index efe0fc78144..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricRegistry; -import jakarta.inject.Inject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.core.MediaType; - -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -@HelidonTest -@TestMethodOrder(MethodOrderer.MethodName.class) -public class MainTest { - - @Inject - private MetricRegistry registry; - - @Inject - private WebTarget target; - - - @Test - public void testMicroprofileMetrics() { - String message = target.path("simple-greet/Joe") - .request() - .get(String.class); - - assertThat(message, is("Hello Joe")); - Counter counter = registry.counter("personalizedGets"); - double before = counter.getCount(); - - message = target.path("simple-greet/Eric") - .request() - .get(String.class); - - assertThat(message, is("Hello Eric")); - double after = counter.getCount(); - assertThat("Difference in personalized greeting counter between successive calls", after - before, is(1d)); - } - - @Test - public void testMetrics() throws Exception { - Response response = target - .path("metrics") - .request() - .get(); - assertThat(response.getStatus(), is(200)); - } - - @Test - public void testHealth() throws Exception { - Response response = target - .path("health") - .request() - .get(); - assertThat(response.getStatus(), is(200)); - } - - @Test - public void testGreet() throws Exception { - GreetingMessage message = target - .path("simple-greet") - .request() - .get(GreetingMessage.class); - assertThat(message.getMessage(), is("Hello World!")); - } - - @Test - public void testGreetings() throws Exception { - GreetingMessage jsonMessage = target - .path("greet/Joe") - .request() - .get(GreetingMessage.class); - assertThat(jsonMessage.getMessage(), is("Hello Joe!")); - - try (Response r = target - .path("greet/greeting") - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat(r.getStatus(), is(204)); - } - - jsonMessage = target - .path("greet/Jose") - .request() - .get(GreetingMessage.class); - assertThat(jsonMessage.getMessage(), is("Hola Jose!")); - } - -} diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java deleted file mode 100644 index f900d6f3ce3..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -import io.helidon.common.http.Http; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * Test-only resource that allows the client to specify what HTTP status the service should return in its response. - * This allows the client to know which status family counter should be updated. - */ -@RequestScoped -@Path("/status") -public class StatusResource { - - @GET - @Produces(MediaType.TEXT_PLAIN) - @Path("/{status}") - public Response reportStatus(@PathParam("status") String statusText) { - int status; - String msg; - try { - status = Integer.parseInt(statusText); - msg = "Successful conversion"; - } catch (NumberFormatException ex) { - status = Http.Status.INTERNAL_SERVER_ERROR_500.code(); - msg = "Unsuccessful conversion"; - } - return Response.status(status).entity(msg).build(); - } -} diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java deleted file mode 100644 index a124a1d3d1c..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.mp.httpstatuscount; - -import io.helidon.common.http.Http; -import io.helidon.microprofile.tests.junit5.AddBean; -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricID; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Tag; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -@HelidonTest -@AddBean(StatusResource.class) -public class StatusTest { - - @Inject - private WebTarget webTarget; - - @Inject - private MetricRegistry metricRegistry; - - private final Counter[] STATUS_COUNTERS = new Counter[6]; - - @BeforeEach - void findStatusMetrics() { - for (int i = 1; i < STATUS_COUNTERS.length; i++) { - STATUS_COUNTERS[i] = metricRegistry.counter(new MetricID(HttpStatusMetricFilter.STATUS_COUNTER_NAME, - new Tag(HttpStatusMetricFilter.STATUS_TAG_NAME, i + "xx"))); - } - } - - @Test - void checkStatusMetrics() { - checkAfterStatus(171); - checkAfterStatus(200); - checkAfterStatus(201); - checkAfterStatus(204); - checkAfterStatus(301); - checkAfterStatus(401); - checkAfterStatus(404); - } - - @Test - void checkStatusAfterGreet() { - long[] before = new long[6]; - for (int i = 1; i < 6; i++) { - before[i] = STATUS_COUNTERS[i].getCount(); - } - Response response = webTarget.path("/greet") - .request(MediaType.APPLICATION_JSON) - .get(); - assertThat("Status of /greet", response.getStatus(), is(Http.Status.OK_200.code())); - checkCounters(response.getStatus(), before); - } - - void checkAfterStatus(int status) { - String path = "/status/" + status; - long[] before = new long[6]; - for (int i = 1; i < 6; i++) { - before[i] = STATUS_COUNTERS[i].getCount(); - } - Response response = webTarget.path(path) - .request(MediaType.TEXT_PLAIN_TYPE) - .get(); - assertThat("Response status", response.getStatus(), is(status)); - checkCounters(status, before); - } - - private void checkCounters(int status, long[] before) { - int family = status / 100; - for (int i = 1; i < 6; i++) { - long expectedDiff = i == family ? 1 : 0; - assertThat("Diff in counter " + family + "xx", STATUS_COUNTERS[i].getCount() - before[i], is(expectedDiff)); - } - } - -} diff --git a/examples/microprofile/http-status-count-mp/src/test/resources/application.yaml b/examples/microprofile/http-status-count-mp/src/test/resources/application.yaml deleted file mode 100644 index 085837b605c..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/resources/application.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2022, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -security: - enabled: false \ No newline at end of file diff --git a/examples/microprofile/idcs/README.md b/examples/microprofile/idcs/README.md deleted file mode 100644 index 5277d382904..00000000000 --- a/examples/microprofile/idcs/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Helidon MP IDCS - -This example demonstrates integration with IDCS (Oracle identity service, integrated with Open ID Connect provider) where JAX-RS application resources are protected by IDCS. - -## Contents - -This project contains two samples, one (IdcsApplication.java) and a second (ReactiveService.java). It also contains a static resource. When configured the example exposes multiple HTTP endpoints. - -### IDCS Configuration - -[This documentation](https://docs.oracle.com/en/cloud/paas/identity-cloud/uaids/oracle-identity-cloud-service.html#GUID-BC4769EE-258A-4B53-AED5-6BA9888C8275) describes basics of IDCS as well as how you can get IDCS instance. - -1. [Log in to the IDCS console](https://docs.oracle.com/en/cloud/paas/identity-cloud/uaids/how-access-oracle-identity-cloud-service.html) and create a new application of type "confidential app" -2. Within **Resources** - 1. Create two resources called `first_scope` and `second_scope` - 2. Primary Audience = `http://localhost:7987/"` (ensure there is a trailing /) -3. Within **Client Configuration** - 1. Register a client - 2. Allowed Grant Types = Client Credentials,JWT Assertion, Refresh Token, Authorization Code - 3. Check "Allow non-HTTPS URLs" - 4. Set Redirect URL to `http://localhost:7987/oidc/redirect` - 5. Client Type = Confidential - 6. Add all Scopes defined in the resources section - 7. Set allowed operations to `Introspect` - 8. Set Post Logout Redirect URL to `http://localhost:7987/loggedout` - -Ensure you save and *activate* the application - -### Application Configuration - -Edit application.yaml based on your IDCS Configuration - -1. idcs-uri : Base URL of your idcs instance, usually something like https://idcs-.identity.oraclecloud.com -2. idcs-client-id : This is obtained from your IDCS application in the IDCS console -3. idcs-client-secret : This is obtained from your IDCS application in the IDCS console -4. frontend-uri : This is the base URL of your application when run, e.g. `http://localhost:7987` -5. proxy-host : Your proxy server if needed -6. scope-audience : This is the scope audience which MUST match the primary audience in the IDCS resource, recommendation is not to have a trailing slash (/) - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-microprofile-security-idcs.jar -``` - -Try the endpoints: - -| Endpoint | Description | -|:------------------------|:---------------------------------------------------------------------------------------| -| `rest/login` | Login | -| `rest/scopes` | Full security with scopes and roles (see IdcsResource.java) | -| `rest/reactive` | Protected reactive service (see application.yaml - security.web-server) | -| `web/resource.html` | Protected static resource (see application.yaml - security.web-server) | diff --git a/examples/microprofile/idcs/pom.xml b/examples/microprofile/idcs/pom.xml deleted file mode 100644 index ae703d2b0fc..00000000000 --- a/examples/microprofile/idcs/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-security-idcs - Helidon Microprofile Examples IDCS Security - - - Microprofile example with IDCS integration (through Open ID Connect) - - - - io.helidon.examples.microprofile.security.idcs.IdcsMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile - helidon-microprofile-oidc - - - io.helidon.security.providers - helidon-security-providers-idcs-mapper - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsApplication.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsApplication.java deleted file mode 100644 index ea7749440ea..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsApplication.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.microprofile.security.idcs; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * Example JAX-RS application with resources protected by IDCS. - */ -@ApplicationScoped -@ApplicationPath("/rest") -public class IdcsApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(IdcsResource.class); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsMain.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsMain.java deleted file mode 100644 index 9b652bb62b3..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsMain.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.microprofile.security.idcs; - -import io.helidon.microprofile.server.Server; - -/** - * IDCS example. - */ -public final class IdcsMain { - private IdcsMain() { - } - - /** - * Start the server and use the application picked up by CDI. - * - * @param args command line arguments, ignored - */ - public static void main(String[] args) { - Server.create().start(); - - System.out.println("Endpoints:"); - System.out.println("Login"); - System.out.println(" http://localhost:7987/rest/login"); - System.out.println("Full security with scopes and roles (see IdcsResource.java)"); - System.out.println(" http://localhost:7987/rest/scopes"); - System.out.println("A protected reactive service (see application.yaml - security.web-server)"); - System.out.println(" http://localhost:7987/reactive"); - System.out.println("A protected static resource (see application.yaml - security.web-server"); - System.out.println(" http://localhost:7987/web/resource.html"); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsResource.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsResource.java deleted file mode 100644 index f77f27dfc5c..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsResource.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.microprofile.security.idcs; - -import io.helidon.security.SecurityContext; -import io.helidon.security.abac.role.RoleValidator; -import io.helidon.security.abac.scope.ScopeValidator; -import io.helidon.security.annotations.Authenticated; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource. - */ -@Path("/") -public class IdcsResource { - /** - * A protected resource (authentication required). - * - * @param context security context that will contain user's subject once login is completed - * @return user's subject as a string - */ - @GET - @Path("/login") - @Authenticated - public String login(@Context SecurityContext context) { - return context.user().toString(); - } - - /** - * A login flow example to use from a HTML frontend. A login button would call this method with a - * query parameter with redirect to the first page. - * - * @param context security context that will contain user's subject once login is completed - * @param redirectTo target URI (relative) to redirect to - * @return redirect response - */ - @GET - @Path("/login2") - @Authenticated - public Response login(@Context SecurityContext context, @QueryParam("target") String redirectTo) { - return Response - .status(Response.Status.TEMPORARY_REDIRECT) - .header("Location", redirectTo) - .build(); - } - - /** - * Authenticated and authorized endpoint that requires two scopes (these must be configure in your IDCS application). - * - * @param context security context - * @return current user's subject as a string, should now contain the scopes required - */ - @GET - @Path("/scopes") - @Authenticated - // Scopes defined in IDCS in my scope audience (see application.yaml) - @ScopeValidator.Scope("first_scope") - @ScopeValidator.Scope("second_scope") - // A group defined in my IDCS domain - @RoleValidator.Roles("my_admins") - public String scopes(@Context SecurityContext context) { - return context.user().toString(); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/ReactiveService.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/ReactiveService.java deleted file mode 100644 index c5f5cea88c8..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/ReactiveService.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.microprofile.security.idcs; - -import io.helidon.microprofile.server.RoutingPath; -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.enterprise.context.ApplicationScoped; - -/** - * Reactive service implementation. - */ -@ApplicationScoped -@RoutingPath("/reactive") -public class ReactiveService implements Service { - - @Override - public void update(Routing.Rules rules) { - rules.get(this::reactiveRoute); - } - - private void reactiveRoute(ServerRequest req, ServerResponse res) { - String username = req.context() - .get(SecurityContext.class) - .flatMap(SecurityContext::user) - .map(Subject::principal) - .map(Principal::getName) - .orElse("not authenticated"); - - res.send("Hello from reactive service, you are " + username); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/package-info.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/package-info.java deleted file mode 100644 index 89aeb0c5644..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of integration with IDCS (through Open ID Connect). - */ -package io.helidon.examples.microprofile.security.idcs; diff --git a/examples/microprofile/idcs/src/main/resources/META-INF/beans.xml b/examples/microprofile/idcs/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/idcs/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/idcs/src/main/resources/WEB/resource.html b/examples/microprofile/idcs/src/main/resources/WEB/resource.html deleted file mode 100644 index 5a16aacbe99..00000000000 --- a/examples/microprofile/idcs/src/main/resources/WEB/resource.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - -Hello, this is a static resource loaded from classpath. -

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


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

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

Uploaded files

-
- -

Upload

-
- Select a file to upload: - - -
- - - - \ No newline at end of file diff --git a/examples/microprofile/multipart/src/main/resources/logging.properties b/examples/microprofile/multipart/src/main/resources/logging.properties deleted file mode 100644 index 5a64db181bb..00000000000 --- a/examples/microprofile/multipart/src/main/resources/logging.properties +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.microprofile.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/microprofile/multipart/src/test/java/io/helidon/examples/microprofile/multipart/FileServiceTest.java b/examples/microprofile/multipart/src/test/java/io/helidon/examples/microprofile/multipart/FileServiceTest.java deleted file mode 100644 index 4f34081888d..00000000000 --- a/examples/microprofile/multipart/src/test/java/io/helidon/examples/microprofile/multipart/FileServiceTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.microprofile.multipart; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import io.helidon.microprofile.server.JaxRsCdiExtension; -import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.microprofile.tests.junit5.AddBean; -import io.helidon.microprofile.tests.junit5.AddExtension; -import io.helidon.microprofile.tests.junit5.DisableDiscovery; -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.json.JsonObject; -import jakarta.json.JsonString; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.glassfish.jersey.client.ClientProperties; -import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider; -import org.glassfish.jersey.media.multipart.MultiPart; -import org.glassfish.jersey.media.multipart.MultiPartFeature; -import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Tests {@link FileService}. - */ -@HelidonTest -@DisableDiscovery -@AddExtension(ServerCdiExtension.class) -@AddExtension(JaxRsCdiExtension.class) -@AddExtension(CdiComponentProvider.class) -@AddBean(FileService.class) -@AddBean(FileStorage.class) -@AddBean(MultiPartFeatureProvider.class) -@TestMethodOrder(OrderAnnotation.class) -public class FileServiceTest { - - @Test - @Order(1) - public void testUpload(WebTarget target) throws IOException { - Path tempDirectory = Files.createTempDirectory(null); - File file = Files.write(tempDirectory.resolve("foo.txt"), "bar\n".getBytes(StandardCharsets.UTF_8)).toFile(); - MultiPart multipart = new MultiPart() - .bodyPart(new FileDataBodyPart("file[]", file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); - try (Response response = target - .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.FALSE) - .register(MultiPartFeature.class) - .path("/api") - .request() - .post(Entity.entity(multipart, MediaType.MULTIPART_FORM_DATA_TYPE))) { - assertThat(response.getStatus(), is(303)); - } - } - - @Test - @Order(2) - public void testList(WebTarget target) { - try (Response response = target - .path("/api") - .request(MediaType.APPLICATION_JSON_TYPE) - .get()) { - assertThat(response.getStatus(), is(200)); - JsonObject json = response.readEntity(JsonObject.class); - assertThat(json, is(notNullValue())); - List files = json.getJsonArray("files").getValuesAs(v -> ((JsonString) v).getString()); - assertThat(files, hasItem("foo.txt")); - } - } - - @Test - @Order(3) - public void testDownload(WebTarget target) throws IOException { - try (Response response = target - .register(MultiPartFeature.class) - .path("/api/foo.txt") - .request(MediaType.APPLICATION_OCTET_STREAM_TYPE) - .get()) { - assertThat(response.getStatus(), is(200)); - assertThat(response.getHeaderString("Content-Disposition"), containsString("filename=\"foo.txt\"")); - InputStream inputStream = response.readEntity(InputStream.class); - assertThat(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8), is("bar\n")); - } - } -} \ No newline at end of file diff --git a/examples/microprofile/multiport/README.md b/examples/microprofile/multiport/README.md deleted file mode 100644 index 50dd7334a32..00000000000 --- a/examples/microprofile/multiport/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Helidon MicroProfile Multiple Port Example - -It is common when deploying a microservice to run your service on -multiple ports so that you can control the visibility of your -service's endpoints. For example you might want to use three ports: - -- 8080: public REST endpoints of application -- 8081: private REST endpoints of application -- 8082: admin endpoints for health, metrics, etc. - -This lets you expose only the public endpoints via your -ingress controller or load balancer. - -This example shows a Helidon JAX-RS application running on three ports -as described above. - -The ports are configured in `application.yaml` by using named sockets. - -Two Applications are defined, each associated with a different socket -using @RoutingName. - -## Build and run - -With JDK11+ -```bash -mvn package -java -jar target/helidon-examples-microprofile-multiport.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/hello - -curl -X GET http://localhost:8081/private/hello - -curl -X GET http://localhost:8082/health - -curl -X GET http://localhost:8082/metrics -``` diff --git a/examples/microprofile/multiport/pom.xml b/examples/microprofile/multiport/pom.xml deleted file mode 100644 index 59fa4a5275d..00000000000 --- a/examples/microprofile/multiport/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-multiport - Helidon Microprofile Examples Multiple Ports - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.config - helidon-config-yaml - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.microprofile.health - helidon-microprofile-health - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-params - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateApplication.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateApplication.java deleted file mode 100644 index 6725c1b6366..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateApplication.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.microprofile.multiport; - -import java.util.Set; - -import io.helidon.microprofile.server.RoutingName; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.core.Application; - -/** - * Application to expose private resource. - */ -@ApplicationScoped -@RoutingName("private") -public class PrivateApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(PrivateResource.class); - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateResource.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateResource.java deleted file mode 100644 index 0d3ecb00c6a..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateResource.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.microprofile.multiport; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * Simple resource. - */ -@RequestScoped -@Path("/private") -public class PrivateResource { - - /** - * Return a private worldly greeting message. - * - * @return {@link String} - */ - @Path("/hello") - @GET - public String helloWorld() { - return "Private Hello World!!"; - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicApplication.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicApplication.java deleted file mode 100644 index 8d1b367d244..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.microprofile.multiport; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.core.Application; - -/** - * Application to expose public resource. - */ -@ApplicationScoped -public class PublicApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(PublicResource.class); - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicResource.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicResource.java deleted file mode 100644 index dcc0b2ed928..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicResource.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.microprofile.multiport; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * Simple resource. - */ -@RequestScoped -@Path("/") -public class PublicResource { - - /** - * Return a worldly greeting message. - * - * @return {@link String} - */ - @Path("/hello") - @GET - public String helloWorld() { - return "Public Hello World!!"; - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/package-info.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/package-info.java deleted file mode 100644 index f438f5b6510..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Application that exposes multiple ports. - */ -package io.helidon.examples.microprofile.multiport; diff --git a/examples/microprofile/multiport/src/main/resources/META-INF/beans.xml b/examples/microprofile/multiport/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/microprofile/multiport/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/multiport/src/main/resources/application.yaml b/examples/microprofile/multiport/src/main/resources/application.yaml deleted file mode 100644 index c826308097e..00000000000 --- a/examples/microprofile/multiport/src/main/resources/application.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -server: - port: 8080 - host: "localhost" - sockets: - - name: "private" - port: 8081 - - name: "admin" - port: 8082 - # bind address is optional, if not defined, server host will be used) - bind-address: "localhost" - -# Metrics and health run on admin port -metrics: - routing: "admin" - -health: - routing: "admin" \ No newline at end of file diff --git a/examples/microprofile/multiport/src/test/java/io/helidon/examples/microprofile/multiport/MainTest.java b/examples/microprofile/multiport/src/test/java/io/helidon/examples/microprofile/multiport/MainTest.java deleted file mode 100644 index 6e15145e295..00000000000 --- a/examples/microprofile/multiport/src/test/java/io/helidon/examples/microprofile/multiport/MainTest.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.microprofile.multiport; - -import java.util.List; -import java.util.stream.Stream; - -import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.microprofile.tests.junit5.AddConfig; -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Unit test for MP multiport example. - */ -@HelidonTest -@AddConfig(key = "server.sockets.0.port", value = "0") // Force ports to be dynamically allocated -@AddConfig(key = "server.sockets.1.port", value = "0") -class MainTest { - // Port names - private static final String ADMIN_PORT = "admin"; - private static final String PRIVATE_PORT = "private"; - private static final String PUBLIC_PORT = "default"; - - private static final String BASE_URL = "http://localhost:"; - - // Used for other (private, admin) ports - private static Client client; - - // Used for the default (public) port which HelidonTest will configure for us - @Inject - private WebTarget publicWebTarget; - - // Needed to get values of dynamically allocated admin and private ports - @Inject - private ServerCdiExtension serverCdiExtension; - - static Stream initParams() { - final String PUBLIC_PATH = "/hello"; - final String PRIVATE_PATH = "/private/hello"; - final String HEALTH_PATH = "/health"; - final String METRICS_PATH = "/metrics"; - - return List.of( - new Params(PUBLIC_PORT, PUBLIC_PATH, Status.OK), - new Params(PUBLIC_PORT, PRIVATE_PATH, Status.NOT_FOUND), - new Params(PUBLIC_PORT, HEALTH_PATH, Status.NOT_FOUND), - new Params(PUBLIC_PORT, METRICS_PATH, Status.NOT_FOUND), - - new Params(PRIVATE_PORT, PUBLIC_PATH, Status.NOT_FOUND), - new Params(PRIVATE_PORT, PRIVATE_PATH, Status.OK), - new Params(PRIVATE_PORT, HEALTH_PATH, Status.NOT_FOUND), - new Params(PRIVATE_PORT, METRICS_PATH, Status.NOT_FOUND), - - new Params(ADMIN_PORT, PUBLIC_PATH, Status.NOT_FOUND), - new Params(ADMIN_PORT, PRIVATE_PATH, Status.NOT_FOUND), - new Params(ADMIN_PORT, HEALTH_PATH, Status.OK), - new Params(ADMIN_PORT, METRICS_PATH, Status.OK) - ).stream(); - } - - @BeforeAll - static void initClass() { - client = ClientBuilder.newClient(); - } - - @AfterAll - static void destroyClass() { - client.close();; - } - - @MethodSource("initParams") - @ParameterizedTest - public void testPortAccess(Params params) { - WebTarget webTarget; - - if (params.portName.equals(PUBLIC_PORT)) { - webTarget = publicWebTarget; - } else { - webTarget = client.target(BASE_URL + serverCdiExtension.port(params.portName)); - } - - try (Response response = webTarget.path(params.path) - .request() - .get()) { - assertThat(webTarget.getUri() + " returned incorrect HTTP status", - response.getStatusInfo().toEnum(), is(params.httpStatus)); - } - } - - @Test - void testEndpoints() { - // Probe PUBLIC port - try (Response response = publicWebTarget.path("/hello") - .request() - .get()) { - assertThat("default port should be serving public resource", - response.getStatusInfo().toEnum(), is(Response.Status.OK)); - assertThat("default port should return public data", - response.readEntity(String.class), is("Public Hello World!!")); - } - - // Probe PRIVATE port - int privatePort = serverCdiExtension.port(PRIVATE_PORT); - WebTarget baseTarget = client.target(BASE_URL + privatePort); - try (Response response = baseTarget.path("/private/hello") - .request() - .get()) { - assertThat("port " + privatePort + " should be serving private resource", - response.getStatusInfo().toEnum(), is(Response.Status.OK)); - assertThat("port " + privatePort + " should return private data", - response.readEntity(String.class), is("Private Hello World!!")); - } - } - - private static class Params { - String portName; - String path; - Response.Status httpStatus; - - private Params(String portName, String path, Response.Status httpStatus) { - this.portName = portName; - this.path = path; - this.httpStatus = httpStatus; - } - - @Override - public String toString() { - return portName + ":" + path + " should return " + httpStatus; - } - } -} diff --git a/examples/microprofile/oidc/README.md b/examples/microprofile/oidc/README.md deleted file mode 100644 index 80f82b7f561..00000000000 --- a/examples/microprofile/oidc/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Security integration with OIDC - -This example demonstrates integration with OIDC (Open ID Connect) providers. - -## Contents - -MP example that integrates with an OIDC provider. - -To configure this example, you need to replace the following: -1. src/main/resources/application.yaml - set security.properties.oidc-* to your tenant and application configuration - -## Running the Example - -Run the "OidcMain" class for file configuration based example. - -## Local configuration - -The example is already set up to read -`${user.home}/helidon/conf/examples.yaml` to override defaults configured -in `application.yaml`. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-microprofile-security-oidc-login.jar -``` diff --git a/examples/microprofile/oidc/pom.xml b/examples/microprofile/oidc/pom.xml deleted file mode 100644 index f9ccef108af..00000000000 --- a/examples/microprofile/oidc/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-security-oidc-login - Helidon Microprofile Examples OIDC Security - - - Microprofile example with (any) OIDC provider integration. - - - - io.helidon.examples.microprofile.security.oidc.OidcMain - - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile - helidon-microprofile-oidc - - - org.jboss - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcMain.java b/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcMain.java deleted file mode 100644 index bef6c09ae09..00000000000 --- a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcMain.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.microprofile.security.oidc; - -import io.helidon.config.Config; -import io.helidon.microprofile.server.Server; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class for MP. - */ -public final class OidcMain { - private OidcMain() { - } - - /** - * Start the application. - * @param args ignored. - */ - public static void main(String[] args) { - Server server = Server.builder() - .config(buildConfig()) - .build() - .start(); - - System.out.println("http://localhost:" + server.port() + "/test"); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcResource.java b/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcResource.java deleted file mode 100644 index c8b28ad36bd..00000000000 --- a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcResource.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.microprofile.security.oidc; - -import io.helidon.security.SecurityContext; -import io.helidon.security.annotations.Authenticated; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Context; - -/** - * A simple JAX-RS resource with a single GET method. - */ -@Path("/test") -public class OidcResource { - - /** - * Hello world using security context. - * @param securityContext context as established during login - * @return a string with current username - */ - @Authenticated - @GET - public String getIt(@Context SecurityContext securityContext) { - return "Hello " + securityContext.userName(); - } - -} diff --git a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/package-info.java b/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/package-info.java deleted file mode 100644 index 598a0f5f907..00000000000 --- a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * An OIDC (Open ID Connect) example. - */ -package io.helidon.examples.microprofile.security.oidc; diff --git a/examples/microprofile/oidc/src/main/resources/META-INF/beans.xml b/examples/microprofile/oidc/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 7785b13b791..00000000000 --- a/examples/microprofile/oidc/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/oidc/src/main/resources/application.yaml b/examples/microprofile/oidc/src/main/resources/application.yaml deleted file mode 100644 index 44773fcfe4c..00000000000 --- a/examples/microprofile/oidc/src/main/resources/application.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# -# 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. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 7987 -security: - config.require-encryption: false - properties: - # this should be defined by the identity server - oidc-identity-uri: "https://tenant.some-server.com/oauth2/default" - # when you create a new client in identity server configuration, you should get a client id and a client secret - oidc-client-id: "some client id" - oidc-client-secret: "some client secret" - # issuer of the tokens - identity server specific (maybe even configurable) - oidc-issuer: "https://tenant.some-server.com/oauth2/default" - # audience of the tokens - identity server specific (usually configurable) - oidc-audience: "configured audience" - # The frontend URI defines the possible load balancer address - # The redirect URI used is ${frontend-uri}${redirect-uri} - # Webserver is by default listening on /oidc/redirect - this can be modified by `redirect-uri` option in oidc configuration - frontend-uri: "http://localhost:7987" - server-type: "@default" - providers: - - abac: - # Adds ABAC Provider - it does not require any configuration - - oidc: - # use a custom name, so it does not clash with other examples - cookie-name: "OIDC_EXAMPLE_COOKIE" - # support for "Authorization" header with bearer token - header-use: true - # the default redirect-uri, where the webserver listens on redirects from identity server - redirect-uri: "/oidc/redirect" - issuer: "${security.properties.oidc-issuer}" - audience: "${security.properties.oidc-audience}" - client-id: "${security.properties.oidc-client-id}" - client-secret: "${security.properties.oidc-client-secret}" - identity-uri: "${security.properties.oidc-identity-uri}" - frontend-uri: "${security.properties.frontend-uri}" - server-type: "${security.properties.server-type}" - # We want to redirect to login page (and token can be received either through cookie or header) - redirect: true \ No newline at end of file diff --git a/examples/microprofile/oidc/src/main/resources/logging.properties b/examples/microprofile/oidc/src/main/resources/logging.properties deleted file mode 100644 index a0f8cb75957..00000000000 --- a/examples/microprofile/oidc/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -# io.helidon.security.providers.oidc.level = FINEST -AUDIT.level=FINEST -# to see detailed information about failed validations of tokens -io.helidon.security.providers.oidc.level=FINEST diff --git a/examples/microprofile/openapi-basic/README.md b/examples/microprofile/openapi-basic/README.md deleted file mode 100644 index b44070fce1f..00000000000 --- a/examples/microprofile/openapi-basic/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Helidon MP Basic OpenAPI Example - -This example shows a simple greeting application, similar to the one from the -Helidon MP QuickStart, enhanced with OpenAPI support. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-microprofile-openapi-basic.jar -``` - -Try the endpoints: - -``` -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/openapi -[lengthy OpenAPI document] -``` -The output describes not only then endpoints from `GreetResource` but -also one contributed by the `SimpleAPIModelReader`. - - diff --git a/examples/microprofile/openapi-basic/pom.xml b/examples/microprofile/openapi-basic/pom.xml deleted file mode 100644 index 608ee0d99da..00000000000 --- a/examples/microprofile/openapi-basic/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-openapi-basic - Helidon Microprofile Example Basic OpenAPI - - - Microprofile example showing basic OpenAPI support - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.openapi - helidon-microprofile-openapi - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - org.jboss - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetResource.java b/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetResource.java deleted file mode 100644 index ad2259d5142..00000000000 --- a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetResource.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.examples.openapi.basic; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.openapi.annotations.Operation; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.ExampleObject; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; - -/** - * A simple JAX-RS resource with OpenAPI annotations to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * Get OpenAPI document for the endpoints - * curl -X GET http://localhost:8080/openapi - * - * Note that the output will include not only the annotated endpoints from this - * class but also an endpoint added by the - * {@link io.helidon.microprofile.examples.openapi.basic.internal.SimpleAPIModelReader}. - * - * The message is returned as a JSON object. - */ -@Path("/greet") -@RequestScoped -public class GreetResource { - - /** - * The greeting message provider. - */ - private final GreetingProvider greetingProvider; - - /** - * Using constructor injection to get a configuration property. - * By default this gets the value from META-INF/microprofile-config - * - * @param greetingConfig the configured greeting message - */ - @Inject - public GreetResource(GreetingProvider greetingConfig) { - this.greetingProvider = greetingConfig; - } - - /** - * Return a worldly greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Operation(summary = "Returns a generic greeting", - description = "Greets the user generically") - @APIResponse(description = "Simple JSON containing the greeting", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class))) - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Operation(summary = "Returns a personalized greeting") - @APIResponse(description = "Simple JSON containing the greeting", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class))) - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Operation(summary = "Set the greeting prefix", - description = "Permits the client to set the prefix part of the greeting (\"Hello\")") - @RequestBody( - name = "greeting", - description = "Conveys the new greeting prefix to use in building greetings", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class), - examples = @ExampleObject( - name = "greeting", - summary = "Example greeting message to update", - value = "{\"greeting\": \"New greeting message\"}"))) - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingMessage.java b/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingMessage.java deleted file mode 100644 index 76c361b1e07..00000000000 --- a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.examples.openapi.basic; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingProvider.java b/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingProvider.java deleted file mode 100644 index 4f08e014349..00000000000 --- a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.examples.openapi.basic; - -import java.util.concurrent.atomic.AtomicReference; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Provider for greeting message. - */ -@ApplicationScoped -public class GreetingProvider { - private final AtomicReference message = new AtomicReference<>(); - - /** - * Create a new greeting provider, reading the message from configuration. - * - * @param message greeting to use - */ - @Inject - public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) { - this.message.set(message); - } - - String getMessage() { - return message.get(); - } - - void setMessage(String message) { - this.message.set(message); - } -} diff --git a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIFilter.java b/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIFilter.java deleted file mode 100644 index e06f133bc20..00000000000 --- a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIFilter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.examples.openapi.basic.internal; - -import java.util.Map; - -import org.eclipse.microprofile.openapi.OASFilter; -import org.eclipse.microprofile.openapi.models.Operation; -import org.eclipse.microprofile.openapi.models.PathItem; - -/** - * Example OpenAPI filter which hides a single endpoint from the OpenAPI document. - */ -public class SimpleAPIFilter implements OASFilter { - - @Override - public PathItem filterPathItem(PathItem pathItem) { - for (Map.Entry methodOp - : pathItem.getOperations().entrySet()) { - if (SimpleAPIModelReader.DOOMED_OPERATION_ID - .equals(methodOp.getValue().getOperationId())) { - return null; - } - } - return OASFilter.super.filterPathItem(pathItem); - } -} diff --git a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIModelReader.java b/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIModelReader.java deleted file mode 100644 index 59ccf9ca8dc..00000000000 --- a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/SimpleAPIModelReader.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.examples.openapi.basic.internal; - -import org.eclipse.microprofile.openapi.OASFactory; -import org.eclipse.microprofile.openapi.OASModelReader; -import org.eclipse.microprofile.openapi.models.OpenAPI; -import org.eclipse.microprofile.openapi.models.PathItem; -import org.eclipse.microprofile.openapi.models.Paths; - -/** - * Defines two paths using the OpenAPI model reader mechanism, one that should - * be suppressed by the filter class and one that should appear in the published - * OpenAPI document. - */ -public class SimpleAPIModelReader implements OASModelReader { - - /** - * Path for the example endpoint added by this model reader that should be visible. - */ - public static final String MODEL_READER_PATH = "/test/newpath"; - - /** - * Path for an endpoint that the filter should hide. - */ - public static final String DOOMED_PATH = "/test/doomed"; - - /** - * ID for an endpoint that the filter should hide. - */ - public static final String DOOMED_OPERATION_ID = "doomedPath"; - - /** - * Summary text for the endpoint. - */ - public static final String SUMMARY = "A sample test endpoint from ModelReader"; - - @Override - public OpenAPI buildModel() { - /* - * Add two path items, one of which we expect to be removed by - * the filter and a very simple one that will appear in the - * published OpenAPI document. - */ - PathItem newPathItem = OASFactory.createPathItem() - .GET(OASFactory.createOperation() - .operationId("newPath") - .summary(SUMMARY)); - PathItem doomedPathItem = OASFactory.createPathItem() - .GET(OASFactory.createOperation() - .operationId(DOOMED_OPERATION_ID) - .summary("This should become invisible")); - OpenAPI openAPI = OASFactory.createOpenAPI(); - Paths paths = OASFactory.createPaths() - .addPathItem(MODEL_READER_PATH, newPathItem) - .addPathItem(DOOMED_PATH, doomedPathItem); - openAPI.paths(paths); - - return openAPI; - } -} diff --git a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/package-info.java b/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/package-info.java deleted file mode 100644 index 8949725e1ec..00000000000 --- a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/internal/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Internal classes supporting Helidon MP OpenAPI. - */ -package io.helidon.microprofile.examples.openapi.basic.internal; diff --git a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/package-info.java b/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/package-info.java deleted file mode 100644 index cf5f401b072..00000000000 --- a/examples/microprofile/openapi-basic/src/main/java/io/helidon/microprofile/examples/openapi/basic/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon MicroProfile OpenAPI basic example. - */ -package io.helidon.microprofile.examples.openapi.basic; diff --git a/examples/microprofile/openapi-basic/src/main/resources/META-INF/beans.xml b/examples/microprofile/openapi-basic/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/microprofile/openapi-basic/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/openapi-basic/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/openapi-basic/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index edf0cc5b362..00000000000 --- a/examples/microprofile/openapi-basic/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -mp.openapi.filter=io.helidon.microprofile.examples.openapi.basic.internal.SimpleAPIFilter -mp.openapi.model.reader=io.helidon.microprofile.examples.openapi.basic.internal.SimpleAPIModelReader diff --git a/examples/microprofile/openapi-basic/src/main/resources/logging.properties b/examples/microprofile/openapi-basic/src/main/resources/logging.properties deleted file mode 100644 index 4029baf371f..00000000000 --- a/examples/microprofile/openapi-basic/src/main/resources/logging.properties +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.microprofile.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/microprofile/openapi-basic/src/test/java/io/helidon/microprofile/examples/openapi/basic/MainTest.java b/examples/microprofile/openapi-basic/src/test/java/io/helidon/microprofile/examples/openapi/basic/MainTest.java deleted file mode 100644 index 652c9fb9bf4..00000000000 --- a/examples/microprofile/openapi-basic/src/test/java/io/helidon/microprofile/examples/openapi/basic/MainTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.examples.openapi.basic; - -import io.helidon.microprofile.examples.openapi.basic.internal.SimpleAPIModelReader; -import io.helidon.microprofile.server.Server; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.spi.CDI; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.JsonPointer; -import jakarta.json.JsonString; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -class MainTest { - private static Server server; - - @BeforeAll - public static void startTheServer() throws Exception { - server = startServer(); - } - - @Test - void testHelloWorld() { - - Client client = ClientBuilder.newClient(); - - GreetingMessage message = client - .target(getConnectionString("/greet")) - .request() - .get(GreetingMessage.class); - assertThat("default message", message.getMessage(), - is("Hello World!")); - - message = client - .target(getConnectionString("/greet/Joe")) - .request() - .get(GreetingMessage.class); - assertThat("hello Joe message", message.getMessage(), - is("Hello Joe!")); - - try (Response r = client - .target(getConnectionString("/greet/greeting")) - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat("PUT status code", r.getStatus(), is(204)); - } - - message = client - .target(getConnectionString("/greet/Jose")) - .request() - .get(GreetingMessage.class); - assertThat("hola Jose message", message.getMessage(), - is("Hola Jose!")); - - client.close(); - } - - @Test - public void testOpenAPI() { - - Client client = ClientBuilder.newClient(); - - JsonObject jsonObject = client - .target(getConnectionString("/openapi")) - .request(MediaType.APPLICATION_JSON) - .get(JsonObject.class); - JsonObject paths = jsonObject.get("paths").asJsonObject(); - - JsonPointer jp = Json.createPointer("/" + escape(SimpleAPIModelReader.MODEL_READER_PATH) + "/get/summary"); - JsonString js = JsonString.class.cast(jp.getValue(paths)); - assertThat("/test/newpath GET summary did not match", js.getString(), is(SimpleAPIModelReader.SUMMARY)); - - jp = Json.createPointer("/" + escape(SimpleAPIModelReader.DOOMED_PATH)); - assertThat("/test/doomed should not appear but does", jp.containsValue(paths), is(false)); - - jp = Json.createPointer("/" + escape("/greet") + "/get/summary"); - js = JsonString.class.cast(jp.getValue(paths)); - assertThat("/greet GET summary did not match", js.getString(), is("Returns a generic greeting")); - - client.close(); - } - - @AfterAll - static void destroyClass() { - CDI current = CDI.current(); - ((SeContainer) current).close(); - } - - private String getConnectionString(String path) { - return "http://localhost:" + server.port() + path; - } - - /** - * Start the server. - * @return the created {@link Server} instance - */ - static Server startServer() { - // Server will automatically pick up configuration from - // microprofile-config.properties - // and Application classes annotated as @ApplicationScoped - return Server.create().start(); - } - - private String escape(String path) { - return path.replace("/", "~1"); - } -} diff --git a/examples/microprofile/openapi-basic/src/test/resources/META-INF/microprofile-config.properties b/examples/microprofile/openapi-basic/src/test/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 242323a4ece..00000000000 --- a/examples/microprofile/openapi-basic/src/test/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +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. -# - - -# Override configuration in main source branch, so we do not use 8080 port for tests -config_ordinal=1000 -# Microprofile server properties -server.port=-1 -server.host=0.0.0.0 diff --git a/examples/microprofile/pom.xml b/examples/microprofile/pom.xml deleted file mode 100644 index e6fbe808eb0..00000000000 --- a/examples/microprofile/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - pom - io.helidon.examples.microprofile - helidon-examples-microprofile-project - Helidon Microprofile Examples - - - graphql - hello-world-implicit - hello-world-explicit - static-content - security - idcs - multipart - oidc - openapi-basic - websocket - messaging-sse - cors - tls - multiport - bean-validation - http-status-count-mp - lra - - diff --git a/examples/microprofile/security/README.md b/examples/microprofile/security/README.md deleted file mode 100644 index 5ca389935a8..00000000000 --- a/examples/microprofile/security/README.md +++ /dev/null @@ -1,28 +0,0 @@ - -# Helidon MP Multiple Applications with Security - -Example MicroProfile application. This has two JAX-RS applications -sharing a common resource accessed through different context roots. - -The resource has multiple endpoints, protected with different -levels of security. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-microprofile-mp1_1-security.jar -``` - -## Endpoints - -Open either of the following in a browser. Once the page loads -click on the links to try and load endpoints restricted to -admin roles or user roles. See the example's `application.yaml` -for the list of user, passwords and roles. - -|Endpoint |Description | -|:-----------|:----------------| -|`static/helloworld`|Public page with no security| -|`other/helloworld`|Same page from second application| - diff --git a/examples/microprofile/security/pom.xml b/examples/microprofile/security/pom.xml deleted file mode 100644 index dac41eb0510..00000000000 --- a/examples/microprofile/security/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-mp1_1-security - Helidon Microprofile Examples MP 1.1 Security - - - Microprofile 1.1 example with security - - - - io.helidon.microprofile.example.security.Main - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.jboss - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/HelloWorldResource.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/HelloWorldResource.java deleted file mode 100644 index 90eefd68a2b..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/HelloWorldResource.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.security; - -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.annotations.Authenticated; -import io.helidon.security.annotations.Authorized; - -import jakarta.annotation.security.RolesAllowed; -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * A dynamic resource that shows a link to the static resource. - */ -@Path("/helloworld") -@RequestScoped -public class HelloWorldResource { - @Inject - private Security security; - @Inject - private SecurityContext securityContext; - - @Inject - @ConfigProperty(name = "server.static.classpath.context") - private String context; - - /** - * Public page (does not require authentication). - * If there is pre-emptive basic auth, it will run within a user context. - * - * @return web page with links to other resources - */ - @GET - @Produces(MediaType.TEXT_HTML) - @Authenticated(optional = true) - public String getPublic() { - return "Hello World. This is a public page with no security " - + "Allowed for admin only
" - + "Allowed for user only
" - + "" + context + "/resource.html allowed for a logged in user
" - + "you are logged in as: " + securityContext.user() - + ""; - } - - /** - * Page restricted to users in "admin" role. - * - * @param securityContext Helidon security context - * @return web page with links to other resources - */ - @GET - @Path("/admin") - @Produces(MediaType.TEXT_HTML) - @Authenticated - @Authorized - @RolesAllowed("admin") - public String getAdmin(@Context SecurityContext securityContext) { - return "Hello World. You may want to check " - + "" + context + "/resource.html
" - + "you are logged in as: " + securityContext.user() - + ""; - } - - /** - * Page restricted to users in "user" role. - * - * @param securityContext Helidon security context - * @return web page with links to other resources - */ - @GET - @Path("/user") - @Produces(MediaType.TEXT_HTML) - @Authenticated - @Authorized - @RolesAllowed("user") - public String getUser(@Context SecurityContext securityContext) { - return "Hello World. You may want to check " - + "" + context + "/resource.html
" - + "you are logged in as: " + securityContext.user() - + ""; - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/Main.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/Main.java deleted file mode 100644 index d8208964207..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/Main.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.security; - -import java.util.concurrent.TimeUnit; - -import io.helidon.microprofile.server.Server; - -/** - * Main class to start the application. - * See resources/META-INF/microprofile-config.properties. - */ -public final class Main { - private Main() { - } - - /** - * Run this example. - * - * @param args command line arguments (ignored) - */ - public static void main(String[] args) { - long now = System.nanoTime(); - - Server server = Server.create(StaticContentApp.class, OtherApp.class) - .start(); - - now = System.nanoTime() - now; - System.out.println("Start server: " + TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS)); - System.out.println("Endpoint available at http://localhost:" + server.port() + "/static/helloworld"); - System.out.println("Alternative endpoint (second application) available at http://localhost:" + server - .port() + "/other/helloworld"); - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/OtherApp.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/OtherApp.java deleted file mode 100644 index 0e4ee0f7c12..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/OtherApp.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.security; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * An example of two applications in a single MP Server. - * This is the "other" application - serving the same resource on a different context. - */ -@ApplicationScoped -@ApplicationPath("/other") -public class OtherApp extends Application { - @Override - public Set> getClasses() { - return Set.of( - HelloWorldResource.class - ); - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/StaticContentApp.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/StaticContentApp.java deleted file mode 100644 index d8666882fe6..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/StaticContentApp.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.security; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * Example JAX-RS application with static content. - */ -@ApplicationScoped -@ApplicationPath("/static") -public class StaticContentApp extends Application { - @Override - public Set> getClasses() { - return Set.of( - HelloWorldResource.class - ); - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/package-info.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/package-info.java deleted file mode 100644 index 52da3d94c29..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Static content example. - */ -package io.helidon.microprofile.example.security; diff --git a/examples/microprofile/security/src/main/resources/META-INF/beans.xml b/examples/microprofile/security/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/security/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/security/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/security/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 40ae4becab8..00000000000 --- a/examples/microprofile/security/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# web server configuration -# Use a random free port -server.port=0 - -# location on classpath (e.g. src/main/resources/WEB in maven) -server.static.classpath.location=/WEB -# this is optional, defaults to "/" -server.static.classpath.context=/static-cp -# server.static.path.location=/content -# server.static.path.context=/static-file diff --git a/examples/microprofile/security/src/main/resources/WEB/resource.html b/examples/microprofile/security/src/main/resources/WEB/resource.html deleted file mode 100644 index 70f019dab5a..00000000000 --- a/examples/microprofile/security/src/main/resources/WEB/resource.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - -Hello, this is a static resource loaded from classpath. -

- The configuration (microprofile config): -


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

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

- The configuration (microprofile config): -


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

- Dynamic page (a hello world) can be found here: /helloworld - - - diff --git a/examples/microprofile/static-content/src/main/resources/logging.properties b/examples/microprofile/static-content/src/main/resources/logging.properties deleted file mode 100644 index 7ea32155049..00000000000 --- a/examples/microprofile/static-content/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -#All attributes details -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL] %4$s %3$s : %5$s%6$s%n -#All log level details -.level=INFO -# Microprofile config -# io.helidon.microprofile.config.level = FINEST -# Microprofile server startup -io.helidon.microprofile.startup.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/microprofile/static-content/src/test/java/io/helidon/microprofile/example/staticc/StaticContentTest.java b/examples/microprofile/static-content/src/test/java/io/helidon/microprofile/example/staticc/StaticContentTest.java deleted file mode 100644 index 6c13214469e..00000000000 --- a/examples/microprofile/static-content/src/test/java/io/helidon/microprofile/example/staticc/StaticContentTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.staticc; - -import java.io.IOException; - -import io.helidon.common.http.Http; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.spi.CDI; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertAll; - -/** - * Unit test for {@link HelloWorldResource}. - */ -class StaticContentTest { - @BeforeAll - static void initClass() throws IOException { - Main.main(new String[0]); - } - - @AfterAll - static void destroyClass() { - CDI current = CDI.current(); - ((SeContainer) current).close(); - } - - @Test - void testDynamicResource() { - String response = ClientBuilder.newClient() - .target("http://localhost:" + Main.getPort() + "/helloworld") - .request() - .get(String.class); - - assertAll("Response must be HTML and contain a ref to static resource", - () -> assertThat(response, containsString("/resource.html")), - () -> assertThat(response, containsString("Hello World")) - ); - } - - @Test - void testWelcomePage() { - try (Response response = ClientBuilder.newClient() - .target("http://localhost:" + Main.getPort()) - .request() - .accept(MediaType.TEXT_HTML_TYPE) - .get()) { - assertThat("Status should be 200", response.getStatus(), is(Http.Status.OK_200.code())); - - String str = response.readEntity(String.class); - - assertAll( - () -> assertThat(response.getMediaType(), is(MediaType.TEXT_HTML_TYPE)), - () -> assertThat(str, containsString("server.static.classpath.location=/WEB")) - ); - } - } - - @Test - void testStaticResource() { - try (Response response = ClientBuilder.newClient() - .target("http://localhost:" + Main.getPort() + "/resource.html") - .request() - .accept(MediaType.TEXT_HTML_TYPE) - .get()) { - assertThat("Status should be 200", response.getStatus(), is(Http.Status.OK_200.code())); - - String str = response.readEntity(String.class); - - assertAll( - () -> assertThat(response.getMediaType(), is(MediaType.TEXT_HTML_TYPE)), - () -> assertThat(str, containsString("server.static.classpath.location=/WEB")) - ); - } - } -} diff --git a/examples/microprofile/static-content/src/test/resources/logging.properties b/examples/microprofile/static-content/src/test/resources/logging.properties deleted file mode 100644 index b5af390c059..00000000000 --- a/examples/microprofile/static-content/src/test/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -.level=INFO -org.jboss.weld.level=INFO diff --git a/examples/microprofile/tls/README.md b/examples/microprofile/tls/README.md deleted file mode 100644 index 4ff2af2ce27..00000000000 --- a/examples/microprofile/tls/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon MP TLS Example - -This examples shows how to configure server TLS using Helidon MP. - -Note: This example uses self-signed server certificate! - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-microprofile-tls.jar -``` -## Exercise the application -```bash -curl -k -X GET https://localhost:8080 -``` diff --git a/examples/microprofile/tls/pom.xml b/examples/microprofile/tls/pom.xml deleted file mode 100644 index 60e6193d5f5..00000000000 --- a/examples/microprofile/tls/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - - io.helidon.examples.microprofile - helidon-examples-microprofile-tls - Helidon Microprofile Examples TLS - - - Microprofile example that configures TLS - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.jboss - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/GreetResource.java b/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/GreetResource.java deleted file mode 100644 index 5237718983b..00000000000 --- a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/GreetResource.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.tls; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.json.JsonObject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * A simple JAX-RS resource to greet you. Examples: - * - * Get default greeting message: - * curl -X GET https://localhost:8080 - * - * The message is returned as a plain text. - */ -@Path("/") -@RequestScoped -public class GreetResource { - - /** - * Return a greeting message. - * - * @return {@link JsonObject} - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String getDefaultMessage() { - return "Hello user!"; - } - -} diff --git a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/Main.java b/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/Main.java deleted file mode 100644 index ab9ad747cc8..00000000000 --- a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/Main.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.example.tls; - -import io.helidon.microprofile.server.Server; - -/** - * Starts the server. - */ -public class Main { - - private Main() { - } - - /** - * Main method. - * - * @param args args - */ - public static void main(String[] args) { - startServer(); - } - - static Server startServer() { - return Server.create().start(); - } - -} diff --git a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/package-info.java b/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/package-info.java deleted file mode 100644 index c2d678945b7..00000000000 --- a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quickstart MicroProfile example. - */ -package io.helidon.microprofile.example.tls; diff --git a/examples/microprofile/tls/src/main/resources/META-INF/beans.xml b/examples/microprofile/tls/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/microprofile/tls/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/tls/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/tls/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index eb65e6a917b..00000000000 --- a/examples/microprofile/tls/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -#Truststore setup -server.tls.trust.keystore.resource.resource-path=server.p12 -server.tls.trust.keystore.passphrase=password -server.tls.trust.keystore.trust-store=true - -#Keystore with private key and server certificate -server.tls.private-key.keystore.resource.resource-path=server.p12 -server.tls.private-key.keystore.passphrase=password diff --git a/examples/microprofile/tls/src/main/resources/logging.properties b/examples/microprofile/tls/src/main/resources/logging.properties deleted file mode 100644 index a71c681ab58..00000000000 --- a/examples/microprofile/tls/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - diff --git a/examples/microprofile/tls/src/main/resources/server.p12 b/examples/microprofile/tls/src/main/resources/server.p12 deleted file mode 100644 index ff8e4ddfc7fc9907376df9a9fb5d453a466c6196..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4133 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 U@+;F6i_J(6+nRj}N+2@-U-0Veh5!Hn diff --git a/examples/microprofile/tls/src/test/java/io/helidon/microprofile/example/tls/TlsTest.java b/examples/microprofile/tls/src/test/java/io/helidon/microprofile/example/tls/TlsTest.java deleted file mode 100644 index 3b882592a07..00000000000 --- a/examples/microprofile/tls/src/test/java/io/helidon/microprofile/example/tls/TlsTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.example.tls; - -import java.net.URI; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import io.helidon.microprofile.server.Server; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Test of the example. - */ -public class TlsTest { - - private static Client client; - static { - - try { - SSLContext sslcontext = SSLContext.getInstance("TLS"); - sslcontext.init(null, new TrustManager[]{new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - }}, new java.security.SecureRandom()); - - client = ClientBuilder.newBuilder() - .sslContext(sslcontext) - .build(); - } catch (Exception e) { - e.printStackTrace(); - } - } - private static Server server; - - @BeforeAll - static void initClass() { - server = Main.startServer(); - server.start(); - } - - @AfterAll - static void destroyClass() { - server.stop(); - } - - @Test - public void testTls() { - URI restUri = URI.create("https://localhost:" + server.port() + "/"); - try (Response res = client.target(restUri).request().get()) { - assertThat(res.getStatus(), is(200)); - assertThat(res.readEntity(String.class), is("Hello user!")); - } - } - -} diff --git a/examples/microprofile/tls/src/test/resources/META-INF/microprofile-config.properties b/examples/microprofile/tls/src/test/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 32b20fab0bd..00000000000 --- a/examples/microprofile/tls/src/test/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Microprofile server properties -server.port=0 - -config_ordinal=500 diff --git a/examples/microprofile/websocket/README.md b/examples/microprofile/websocket/README.md deleted file mode 100644 index 64ae0882325..00000000000 --- a/examples/microprofile/websocket/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Helidon MP WebSocket Example - -This examples shows a simple application written using Helidon MP -that combines REST resources and WebSocket endpoints. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-microprofile-websocket.jar -``` - -``` -http://localhost:7001/web/index.html -``` diff --git a/examples/microprofile/websocket/pom.xml b/examples/microprofile/websocket/pom.xml deleted file mode 100644 index cc4beb037c7..00000000000 --- a/examples/microprofile/websocket/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-websocket - Helidon Microprofile Examples WebSocket - - - Microprofile example that uses websockets - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.websocket - helidon-microprofile-websocket - - - org.jboss - jandex - runtime - true - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageBoardEndpoint.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageBoardEndpoint.java deleted file mode 100644 index de51c01416a..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageBoardEndpoint.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.websocket; - -import java.io.IOException; -import java.util.logging.Logger; - -import jakarta.inject.Inject; -import jakarta.websocket.Encoder; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnError; -import jakarta.websocket.OnMessage; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -/** - * Class MessageBoardEndpoint. - */ -@ServerEndpoint( - value = "/websocket", - encoders = { MessageBoardEndpoint.UppercaseEncoder.class } -) -public class MessageBoardEndpoint { - private static final Logger LOGGER = Logger.getLogger(MessageBoardEndpoint.class.getName()); - - @Inject - private MessageQueue messageQueue; - - /** - * OnOpen call. - * - * @param session The websocket session. - * @throws IOException If error occurs. - */ - @OnOpen - public void onOpen(Session session) throws IOException { - LOGGER.info("OnOpen called"); - } - - /** - * OnMessage call. - * - * @param session The websocket session. - * @param message The message received. - * @throws Exception If error occurs. - */ - @OnMessage - public void onMessage(Session session, String message) throws Exception { - LOGGER.info("OnMessage called '" + message + "'"); - - // Send all messages in the queue - if (message.equals("SEND")) { - while (!messageQueue.isEmpty()) { - session.getBasicRemote().sendObject(messageQueue.pop()); - } - } - } - - /** - * OnError call. - * - * @param t The throwable. - */ - @OnError - public void onError(Throwable t) { - LOGGER.info("OnError called"); - } - - /** - * OnError call. - * - * @param session The websocket session. - */ - @OnClose - public void onClose(Session session) { - LOGGER.info("OnClose called"); - } - - /** - * Uppercase encoder. - */ - public static class UppercaseEncoder implements Encoder.Text { - - @Override - public String encode(String s) { - LOGGER.info("UppercaseEncoder encode called"); - return s.toUpperCase(); - } - - @Override - public void init(EndpointConfig config) { - } - - @Override - public void destroy() { - } - } -} diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueue.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueue.java deleted file mode 100644 index 5f1dc870058..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueue.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.websocket; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -import jakarta.enterprise.context.ApplicationScoped; - -/** - * Class MessageQueue. - */ -@ApplicationScoped -public class MessageQueue { - - private Queue queue = new ConcurrentLinkedQueue<>(); - - /** - * Push string on stack. - * - * @param s String to push. - */ - public void push(String s) { - queue.add(s); - } - - /** - * Pop string from stack. - * - * @return The string or {@code null}. - */ - public String pop() { - return queue.poll(); - } - - /** - * Check if stack is empty. - * - * @return Outcome of test. - */ - public boolean isEmpty() { - return queue.isEmpty(); - } - - /** - * Peek at stack without changing it. - * - * @return String peeked or {@code null}. - */ - public String peek() { - return queue.peek(); - } -} diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueueResource.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueueResource.java deleted file mode 100644 index 66600887c74..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueueResource.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.websocket; - -import java.util.logging.Logger; - -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; - -/** - * Class MessageQueueResource. - */ -@Path("rest") -public class MessageQueueResource { - - private static final Logger LOGGER = Logger.getLogger(MessageQueueResource.class.getName()); - - @Inject - private MessageQueue messageQueue; - - /** - * Resource to push string into queue. - * - * @param s The string. - */ - @POST - @Consumes("text/plain") - public void push(String s) { - LOGGER.info("push called '" + s + "'"); - messageQueue.push(s); - } -} diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/package-info.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/package-info.java deleted file mode 100644 index 7ce7ebb94a7..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon WebSocket example. - */ -package io.helidon.microprofile.example.websocket; diff --git a/examples/microprofile/websocket/src/main/resources/META-INF/beans.xml b/examples/microprofile/websocket/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/microprofile/websocket/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/websocket/src/main/resources/WEB/index.html b/examples/microprofile/websocket/src/main/resources/WEB/index.html deleted file mode 100644 index 3a61754614d..00000000000 --- a/examples/microprofile/websocket/src/main/resources/WEB/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - -

-
-

-

- -

-

- -

-

-

History

-
-
- - \ No newline at end of file diff --git a/examples/microprofile/websocket/src/main/resources/application.yaml b/examples/microprofile/websocket/src/main/resources/application.yaml deleted file mode 100644 index b0a388c6079..00000000000 --- a/examples/microprofile/websocket/src/main/resources/application.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 7001 - # location on classpath (e.g. src/main/resources/WEB in maven) - static.classpath: - location: "/WEB" - context: "/web" \ No newline at end of file diff --git a/examples/microprofile/websocket/src/main/resources/logging.properties b/examples/microprofile/websocket/src/main/resources/logging.properties deleted file mode 100644 index 24de00b0293..00000000000 --- a/examples/microprofile/websocket/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.server.level=INFO diff --git a/examples/microprofile/websocket/src/test/java/io/helidon/microprofile/example/websocket/MessageBoardTest.java b/examples/microprofile/websocket/src/test/java/io/helidon/microprofile/example/websocket/MessageBoardTest.java deleted file mode 100644 index 7c29fc4d89c..00000000000 --- a/examples/microprofile/websocket/src/test/java/io/helidon/microprofile/example/websocket/MessageBoardTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.example.websocket; - -import java.io.IOException; -import java.net.URI; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.websocket.ClientEndpointConfig; -import jakarta.websocket.CloseReason; -import jakarta.websocket.DeploymentException; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.MessageHandler; -import jakarta.websocket.Session; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import org.glassfish.tyrus.client.ClientManager; -import org.glassfish.tyrus.container.jdk.client.JdkClientContainer; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Class MessageBoardTest. - */ -@HelidonTest -class MessageBoardTest { - private static final Logger LOGGER = Logger.getLogger(MessageBoardTest.class.getName()); - private static final String[] MESSAGES = { "Whisky", "Tango", "Foxtrot" }; - - private final WebTarget webTarget; - private final ServerCdiExtension server; - private final ClientManager websocketClient = ClientManager.createClient(JdkClientContainer.class.getName()); - - @Inject - MessageBoardTest(WebTarget webTarget, ServerCdiExtension server) { - this.webTarget = webTarget; - this.server = server; - } - - @Test - public void testBoard() throws IOException, DeploymentException, InterruptedException { - // Post messages using REST resource - for (String message : MESSAGES) { - try (Response res = webTarget.path("/rest").request().post(Entity.text(message))) { - assertThat(res.getStatus(), is(204)); - LOGGER.info("Posting message '" + message + "'"); - } - } - - // Now connect to message board using WS and them back - URI websocketUri = URI.create("ws://localhost:" + server.port() + "/websocket"); - CountDownLatch messageLatch = new CountDownLatch(MESSAGES.length); - ClientEndpointConfig config = ClientEndpointConfig.Builder.create().build(); - - websocketClient.connectToServer(new Endpoint() { - @Override - public void onOpen(Session session, EndpointConfig EndpointConfig) { - try { - // Set message handler to receive messages - session.addMessageHandler(new MessageHandler.Whole() { - @Override - public void onMessage(String message) { - LOGGER.info("Client OnMessage called '" + message + "'"); - messageLatch.countDown(); - if (messageLatch.getCount() == 0) { - try { - session.close(); - } catch (IOException e) { - fail("Unexpected exception " + e); - } - } - } - }); - - // Send an initial message to start receiving - session.getBasicRemote().sendText("SEND"); - } catch (IOException e) { - fail("Unexpected exception " + e); - } - } - - @Override - public void onClose(Session session, CloseReason closeReason) { - LOGGER.info("Client OnClose called '" + closeReason + "'"); - } - - @Override - public void onError(Session session, Throwable thr) { - LOGGER.info("Client OnError called '" + thr + "'"); - - } - }, config, websocketUri); - - // Wait until all messages are received - assertThat("Message latch should have counted down to 0", - messageLatch.await(1000, TimeUnit.SECONDS), - is(true)); - } -} diff --git a/examples/openapi-tools/README.md b/examples/openapi-tools/README.md deleted file mode 100644 index c043e0cc545..00000000000 --- a/examples/openapi-tools/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# OpenApi Tools Examples - -This directory contains OpenApi Tools examples for Helidon SE/MP clients and servers. diff --git a/examples/openapi-tools/pom.xml b/examples/openapi-tools/pom.xml deleted file mode 100644 index b840248cbb6..00000000000 --- a/examples/openapi-tools/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - pom - io.helidon.examples.openapi.tools - helidon-examples-openapi-tools-project - Helidon OpenApi Tools Examples - - - quickstart-mp - quickstart-se - - diff --git a/examples/openapi-tools/quickstart-mp/README.md b/examples/openapi-tools/quickstart-mp/README.md deleted file mode 100644 index d87a0acb6d1..00000000000 --- a/examples/openapi-tools/quickstart-mp/README.md +++ /dev/null @@ -1,280 +0,0 @@ -# Helidon OpenAPI Generator example for Helidon MP server and client - -The goal of this example is to show how a user can easily create a Helidon MP server or client from an OpenAPI document using OpenAPI Generator. - -Here we will show the steps that a user has to do to create Helidon MP server and client using OpenAPI Generator and what has to be done to make the generated server and client fully functional. - -For generation of our projects we will use `openapi-generator-cli.jar` that can be downloaded from the maven repository (instructions and other options can be found [here](https://openapi-generator.tech/docs/installation)) and OpenAPI document `quickstart.yaml` that can be found next to this `README.md`. - -## Build, prepare and run the Helidon MP server - -To generate Helidon MP server at first we create `mp-server` folder and then inside it we run the following command where `path-to-generator` is the directory where you downloaded the generator CLI JAR file and `path-to-openapi-doc` is the folder where `quickstart.yaml` is located: -```bash -java -jar path-to-generator/openapi-generator-cli.jar \ - generate \ - -g java-helidon-server \ - --library mp \ - -i path-to-openapi-doc/quickstart.yaml -``` - -When this command finishes its work in the folder `mp-server` we will find the generated project where the most interesting parts are located inside `api` and `model` packages. -The package `api` contains interfaces that represent endpoints for our server and implementations with stubs for them. -These implementations we need to change to implement our business logic. -The package `model` contains classes that represent transport objects that will be used by our endpoints to receive requests and send responses. - -Let's change a little class `MessageServiceImpl` for our example : -1) Add annotation `@ApplicationScoped` to this class. -2) Add field that will contain default message for our endpoints : -```java - private final AtomicReference defaultMessage = new AtomicReference<>(); -``` -3) Add default constructor to the class : -```java - public MessageServiceImpl() { - Message message = new Message(); - message.setMessage("World"); - message.setGreeting("Hello"); - defaultMessage.set(message); - } -``` -4) Replace implementation of the method `public Message getDefaultMessage()` by this: -```java - return defaultMessage.get(); -``` -5) Replace implementation of the method `public Message getMessage(@PathParam("name") String name)` by this: -```java - Message result = new Message(); - return result.message(name).greeting(defaultMessage.get().getGreeting()); -``` -6) Replace implementation of the method `public Response updateGreeting(@Valid @NotNull Message message)` by this: -```java - defaultMessage.set(message); - Response.status(Response.Status.NO_CONTENT).build(); -``` - -To run the application : - -With JDK17+ -```bash -mvn package -java -jar target/openapi-java-server.jar -``` - -To check that server works as expected run the following `curl` commands : - -``` -curl -X GET http://localhost:8080/greet -{"message":"World","greeting":"Hello"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Joe","greeting":"Hello"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola", "message":"Lisa"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet -{"message":"Lisa","greeting":"Hola"} -``` - -## Build, prepare and run the Helidon MP client - -The second part of this example is generating MicroProfile Rest Client that will communicate with the server that we have just created. - -To generate Helidon MP client at first we create `mp-client` folder and then inside it we run the following command where `path-to-generator` is the directory where you downloaded the generator CLI JAR file and `path-to-openapi-doc` is the folder where `quickstart.yaml` is located: -```bash -java -jar path-to-generator/openapi-generator-cli.jar \ - generate \ - -g java-helidon-client \ - --library mp \ - -i path-to-openapi-doc/quickstart.yaml -``` - -When this command finishes its work in the folder `mp-client` we will find the generated project. -As with server project there is the most interesting part are located inside `api` and `model` packages. -The package `api` contains interfaces that represent endpoints to our server. -The package `model` contains classes that represent transport objects that will be used to communicate with the server. - -You can use the generated MP client artifact in either of two ways: - - - as a library - One or more other client projects can depend on the client artifact and use its generated classes. - - as a client program itself - Add some code to the generated project to make it a client program and not just a library. - -This example illustrates the second approach. We create a second server (at port 8081) which accepts greeting requests and, acting as a client, forwards them to the first service and returns the responses from the first service as its own. - -To make our client application fully functional let's add some classes, dependencies and files to the project. - -1) Let's add a class `MessageService` that will use `MessageApi` interface to interact with the server : -```java -@Path("/greet") -@ApplicationScoped -public class MessageService { - - @Inject - @RestClient - private MessageApi messageApi; - - - @GET - @Produces({"application/json"}) - public Message getDefaultMessage() throws ApiException { - return messageApi.getDefaultMessage(); - } - - @GET - @Path("/{name}") - @Produces({"application/json"}) - public Message getMessage(@PathParam("name") String name) throws ApiException { - return messageApi.getMessage(name); - } - - @PUT - @Path("/greeting") - @Consumes({"application/json"}) - public void updateGreeting(Message message) throws ApiException { - messageApi.updateGreeting(message); - } -} -``` - -2) Create the directory `src/main/resources/META-INF`. -3) Add file `beans.xml` inside the folder `META-INF` : -```xml - - - - -``` -4) Add file `microprofile-config.properties` inside the folder `META-INF` : -```properties -# Microprofile server properties -server.port=8081 -server.host=0.0.0.0 -``` -5) Add dependency in `pom.xml` : -```xml - - io.helidon.microprofile.bundles - helidon-microprofile-core - -``` -6) In the file `MessageApi` replace the line: -```java -@RegisterRestClient -``` -to -```java -@RegisterRestClient(baseUri="http://localhost:8080") -``` - -To run the application : - -With JDK17+ -```bash -mvn package -java -jar target/openapi-java-client.jar -``` - -To check that the client works as expected and process all the requests using our server run the following `curl` commands : - -``` -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hi", "message":"Mike"}' http://localhost:8081/greet/greeting - -curl -X GET http://localhost:8081/greet -{"message":"Mike","greeting":"Hi"} - -curl -X GET http://localhost:8081/greet/Joe -{"message":"Joe","greeting":"Hi"} -``` - -## Update applications - -To keep the server and the client up to date according to the OpenApi document, we can use the maven plugin `openapi-generator-maven-plugin`. - -Add these lines to the `pom.xml` of our server : -```xml - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/META-INF/openapi.yml - java-helidon-server - mp - ${project.basedir} - - false - - - - - - - - - -``` - -For the client application : -1) Copy OpenApi document `path-to-openapi-doc/quickstart.yaml` to the folder `META-INF` and rename it to `openapi.yaml`. -2) Add these lines to the `pom.xml` of our client : -```xml - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/META-INF/openapi.yml - java-helidon-client - mp - ${project.basedir} - - false - - - - - - - - - -``` - -Also add the following to the `` in the `pom.xml` file: -```xml -6.2.1 -``` - -The version `6.2.1` was the first version where Helidon generators were added, so if more modern versions of this plugin are exist you can choose one of them. - -To run the generator during your build, invoke the profile: `mvn clean package -P openapi`. - -It should also be added that the `fullProject` option was used in the plugin configuration. -If it set to true, it will generate all files; if set to false, it will only generate API files. -If unspecified, the behavior depends on whether a project exists or not: if it does not, same as true; if it does, same as false. -So keep in mind that regenerating will overwrite your customized `MessageService` or `Message` files and you will need to add the customization again after regenerating. -Note that test files are never overwritten. diff --git a/examples/openapi-tools/quickstart-mp/mp-client/README.md b/examples/openapi-tools/quickstart-mp/mp-client/README.md deleted file mode 100644 index 43e75a89b5b..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# OpenAPI Helidon Quickstart - -This is a sample for Helidon Quickstart project. - - -## Overview -This project was generated using the Helidon OpenAPI Generator. diff --git a/examples/openapi-tools/quickstart-mp/mp-client/docs/Message.md b/examples/openapi-tools/quickstart-mp/mp-client/docs/Message.md deleted file mode 100644 index df42a18ce87..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/docs/Message.md +++ /dev/null @@ -1,15 +0,0 @@ - - -# Message - -An message for the user - -## Properties - -| Name | Type | Description | Notes | -|------------ | ------------- | ------------- | -------------| -|**message** | **String** | | [optional] | -|**greeting** | **String** | | [optional] | - - - diff --git a/examples/openapi-tools/quickstart-mp/mp-client/docs/MessageApi.md b/examples/openapi-tools/quickstart-mp/mp-client/docs/MessageApi.md deleted file mode 100644 index c35f4f4057c..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/docs/MessageApi.md +++ /dev/null @@ -1,108 +0,0 @@ -# MessageApi - -All URIs are relative to *http://localhost:8080* - -| Method | HTTP request | Description | -|------------- | ------------- | -------------| -| [**getDefaultMessage**](MessageApi.md#getDefaultMessage) | **GET** /greet | Return a worldly greeting message. | -| [**getMessage**](MessageApi.md#getMessage) | **GET** /greet/{name} | Return a greeting message using the name that was provided. | -| [**updateGreeting**](MessageApi.md#updateGreeting) | **PUT** /greet/greeting | Set the greeting to use in future messages. | - - - -## getDefaultMessage - -> Message getDefaultMessage() - -Return a worldly greeting message. - -### Parameters - -This endpoint does not need any parameter. - -### Return type - -[**Message**](Message.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: application/json - - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -| **200** | successful operation | - | - - -## getMessage - -> Message getMessage(name) - -Return a greeting message using the name that was provided. - -### Parameters - - -| Name | Type | Description | Notes | -|------------- | ------------- | ------------- | -------------| -| **name** | **String**| the name to greet | | - -### Return type - -[**Message**](Message.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: application/json - - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -| **200** | successful operation | - | - - -## updateGreeting - -> void updateGreeting(message) - -Set the greeting to use in future messages. - -### Parameters - - -| Name | Type | Description | Notes | -|------------- | ------------- | ------------- | -------------| -| **message** | [**Message**](Message.md)| Message for the user | | - -### Return type - -[**void**](Void.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: application/json -- **Accept**: Not defined - - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -| **200** | successful operation | - | -| **400** | No greeting provided | - | - diff --git a/examples/openapi-tools/quickstart-mp/mp-client/pom.xml b/examples/openapi-tools/quickstart-mp/mp-client/pom.xml deleted file mode 100644 index eed131afd9a..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/pom.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - 4.0.0 - org.openapitools - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - openapi-mp-client - openapi-java-client - 1.0.0 - https://github.com/openapitools/openapi-generator - OpenAPI Java - jar - - - 6.2.1 - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.rest-client - helidon-microprofile-rest-client - - - io.helidon.microprofile.config - helidon-microprofile-config - - - org.glassfish.jersey.ext.cdi - jersey-cdi1x - - - jakarta.enterprise - jakarta.enterprise.cdi-api - - - jakarta.json - jakarta.json-api - - - org.glassfish.jersey.media - jersey-media-json-jackson - - - org.openapitools - jackson-databind-nullable - 0.2.2 - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/META-INF/openapi.yml - java-helidon-client - mp - ${project.basedir} - - false - - - - - - - - - - diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/JavaTimeFormatter.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/JavaTimeFormatter.java deleted file mode 100644 index f05bc01724f..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/JavaTimeFormatter.java +++ /dev/null @@ -1,74 +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 org.openapitools.client; - -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; - -/** - * Class that add parsing/formatting support for Java 8+ {@code OffsetDateTime} class. - * It's generated for java clients when {@code AbstractJavaCodegen#dateLibrary} specified as {@code java8}. - */ -@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaHelidonClientCodegen", date = "2022-10-25T13:34" - + ":54.065731594+02:00[Europe/Prague]") -public class JavaTimeFormatter { - - private DateTimeFormatter offsetDateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; - - /** - * Get the date format used to parse/format {@code OffsetDateTime} parameters. - * - * @return DateTimeFormatter - */ - public DateTimeFormatter getOffsetDateTimeFormatter() { - return offsetDateTimeFormatter; - } - - /** - * Set the date format used to parse/format {@code OffsetDateTime} parameters. - * - * @param offsetDateTimeFormatter {@code DateTimeFormatter} - */ - public void setOffsetDateTimeFormatter(DateTimeFormatter offsetDateTimeFormatter) { - this.offsetDateTimeFormatter = offsetDateTimeFormatter; - } - - /** - * Parse the given string into {@code OffsetDateTime} object. - * - * @param str String - * @return {@code OffsetDateTime} - */ - public OffsetDateTime parseOffsetDateTime(String str) { - try { - return OffsetDateTime.parse(str, offsetDateTimeFormatter); - } catch (DateTimeParseException e) { - throw new RuntimeException(e); - } - } - - /** - * Format the given {@code OffsetDateTime} object into string. - * - * @param offsetDateTime {@code OffsetDateTime} - * @return {@code OffsetDateTime} in string format - */ - public String formatOffsetDateTime(OffsetDateTime offsetDateTime) { - return offsetDateTimeFormatter.format(offsetDateTime); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java deleted file mode 100644 index da9e5d4095a..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java +++ /dev/null @@ -1,61 +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 org.openapitools.client; - -import com.fasterxml.jackson.databind.util.StdDateFormat; - -import java.text.DateFormat; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.util.Date; -import java.text.DecimalFormat; -import java.util.GregorianCalendar; -import java.util.TimeZone; - -public class RFC3339DateFormat extends DateFormat { - private static final long serialVersionUID = 1L; - private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); - - private final StdDateFormat fmt = new StdDateFormat() - .withTimeZone(TIMEZONE_Z) - .withColonInTimeZone(true); - - public RFC3339DateFormat() { - this.calendar = new GregorianCalendar(); - this.numberFormat = new DecimalFormat(); - } - - @Override - public Date parse(String source) { - return parse(source, new ParsePosition(0)); - } - - @Override - public Date parse(String source, ParsePosition pos) { - return fmt.parse(source, pos); - } - - @Override - public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { - return fmt.format(date, toAppendTo, fieldPosition); - } - - @Override - public Object clone() { - return super.clone(); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiException.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiException.java deleted file mode 100644 index 4356a82295d..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiException.java +++ /dev/null @@ -1,34 +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 org.openapitools.client.api; - -import jakarta.ws.rs.core.Response; - -public class ApiException extends Exception { - private static final long serialVersionUID = 1L; - - private final Response response; - - public ApiException(Response response) { - super("Api response has status code " + response.getStatus()); - this.response = response; - } - - public Response getResponse() { - return this.response; - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiExceptionMapper.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiExceptionMapper.java deleted file mode 100644 index e0a364b39d7..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/ApiExceptionMapper.java +++ /dev/null @@ -1,36 +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 org.openapitools.client.api; - -import jakarta.ws.rs.core.MultivaluedMap; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.Provider; -import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper; - -@Provider -public class ApiExceptionMapper implements ResponseExceptionMapper { - - @Override - public boolean handles(int status, MultivaluedMap headers) { - return status >= 400; - } - - @Override - public ApiException toThrowable(Response response) { - return new ApiException(response); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageApi.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageApi.java deleted file mode 100644 index e7c35b685de..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageApi.java +++ /dev/null @@ -1,62 +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 org.openapitools.client.api; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.ProcessingException; -import jakarta.ws.rs.Produces; -import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; -import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; -import org.openapitools.client.model.Message; - -/** - * OpenAPI Helidon Quickstart - * - *

This is a sample for Helidon Quickstart project. - */ -@RegisterRestClient(baseUri = "http://localhost:8080") -@RegisterProvider(ApiExceptionMapper.class) -@Path("/greet") -public interface MessageApi { - - /** - * Return a worldly greeting message. - */ - @GET - @Produces({"application/json"}) - Message getDefaultMessage() throws ApiException, ProcessingException; - - /** - * Return a greeting message using the name that was provided. - */ - @GET - @Path("/{name}") - @Produces({"application/json"}) - Message getMessage(@PathParam("name") String name) throws ApiException, ProcessingException; - - /** - * Set the greeting to use in future messages. - */ - @PUT - @Path("/greeting") - @Consumes({"application/json"}) - void updateGreeting(Message message) throws ApiException, ProcessingException; -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageService.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageService.java deleted file mode 100644 index 61a6ff455fa..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/MessageService.java +++ /dev/null @@ -1,80 +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 org.openapitools.client.api; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import org.eclipse.microprofile.rest.client.inject.RestClient; -import org.openapitools.client.model.Message; - -/** - * MessageService. - */ -@Path("/greet") -@ApplicationScoped -public class MessageService { - - @Inject - @RestClient - private MessageApi messageApi; - - - /** - * Return a worldly greeting message. - * - * @return a worldly greeting message. - * @throws ApiException - */ - @GET - @Produces({"application/json"}) - public Message getDefaultMessage() throws ApiException { - return messageApi.getDefaultMessage(); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name name for message. - * @return a greeting message. - * @throws ApiException - */ - @GET - @Path("/{name}") - @Produces({"application/json"}) - public Message getMessage(@PathParam("name") String name) throws ApiException { - return messageApi.getMessage(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message message to set. - * @throws ApiException - */ - @PUT - @Path("/greeting") - @Consumes({"application/json"}) - public void updateGreeting(Message message) throws ApiException { - messageApi.updateGreeting(message); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/package-info.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/package-info.java deleted file mode 100644 index 859f84d62dd..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/api/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. - */ - -/** - * API package. - */ -package org.openapitools.client.api; diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/Message.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/Message.java deleted file mode 100644 index 4d9c2914c31..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/Message.java +++ /dev/null @@ -1,95 +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 org.openapitools.client.model; - -/** - * An message for the user - **/ -public class Message { - - private String message; - - private String greeting; - - /** - * Get message - * - * @return message - **/ - public String getMessage() { - return message; - } - - /** - * Set message - **/ - public void setMessage(String message) { - this.message = message; - } - - public Message message(String message) { - this.message = message; - return this; - } - - /** - * Get greeting - * - * @return greeting - **/ - public String getGreeting() { - return greeting; - } - - /** - * Set greeting - **/ - public void setGreeting(String greeting) { - this.greeting = greeting; - } - - public Message greeting(String greeting) { - this.greeting = greeting; - return this; - } - - - /** - * Create a string representation of this pojo. - **/ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Message {\n"); - - sb.append(" message: ").append(toIndentedString(message)).append("\n"); - sb.append(" greeting: ").append(toIndentedString(greeting)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private static String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/package-info.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/package-info.java deleted file mode 100644 index 6e232df82ec..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/model/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. - */ - -/** - * Model package. - */ -package org.openapitools.client.model; diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/package-info.java b/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/package-info.java deleted file mode 100644 index ef370c991f5..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/java/org/openapitools/client/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon MP client. - */ -package org.openapitools.client; diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/beans.xml b/examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4e2030d4e9a..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/microprofile-config.properties b/examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index e70fd1ec721..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Microprofile server properties -server.port=8081 -server.host=0.0.0.0 diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/api/MessageApiTest.java b/examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/api/MessageApiTest.java deleted file mode 100644 index cb32b8fbc04..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/api/MessageApiTest.java +++ /dev/null @@ -1,89 +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 org.openapitools.client.api; - -import org.openapitools.client.model.Message; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import org.eclipse.microprofile.rest.client.RestClientBuilder; - -import java.net.URL; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * OpenAPI Helidon Quickstart Test - * - * API tests for MessageApi - */ -public class MessageApiTest { - - private static MessageApi client; - private static final String baseUrl = "http://localhost:8080"; - - @BeforeAll - public static void setup() throws MalformedURLException { - client = RestClientBuilder.newBuilder() - .baseUrl(new URL(baseUrl)) - .register(ApiException.class) - .build(MessageApi.class); - } - - - /** - * Return a worldly greeting message. - * - * @throws ApiException - * if the Api call fails - */ - @Test - public void getDefaultMessageTest() throws Exception { - //Message response = client.getDefaultMessage(); - //assertNotNull(response); - } - - /** - * Return a greeting message using the name that was provided. - * - * @throws ApiException - * if the Api call fails - */ - @Test - public void getMessageTest() throws Exception { - //Message response = client.getMessage(name); - //assertNotNull(response); - } - - /** - * Set the greeting to use in future messages. - * - * @throws ApiException - * if the Api call fails - */ - @Test - public void updateGreetingTest() throws Exception { - //void response = client.updateGreeting(message); - //assertNotNull(response); - } - -} diff --git a/examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/model/MessageTest.java b/examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/model/MessageTest.java deleted file mode 100644 index 8286df28f90..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-client/src/test/java/org/openapitools/client/model/MessageTest.java +++ /dev/null @@ -1,58 +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 org.openapitools.client.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.annotation.JsonValue; - -import org.junit.jupiter.api.Test; - - -/** - * Model tests for Message - */ -public class MessageTest { - private final Message model = new Message(); - - /** - * Model tests for Message - */ - @Test - public void testMessage() { - // TODO: test Message - } - - /** - * Test the property 'message' - */ - @Test - public void messageTest() { - // TODO: test message - } - - /** - * Test the property 'greeting' - */ - @Test - public void greetingTest() { - // TODO: test greeting - } - -} diff --git a/examples/openapi-tools/quickstart-mp/mp-server/README.md b/examples/openapi-tools/quickstart-mp/mp-server/README.md deleted file mode 100644 index cfe0795dbca..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Helidon Server with OpenAPI - -## Build and run - -With JDK11+ -```bash -mvn package -java -jar target/openapi-java-server.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080 -curl -X GET http://localhost:8080/{name} -curl -X PUT http://localhost:8080/greeting - -``` - -## Try health and metrics - -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... -. . . - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge -. . . - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -{"base":... -. . . -``` \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-mp/mp-server/pom.xml b/examples/openapi-tools/quickstart-mp/mp-server/pom.xml deleted file mode 100644 index 424e3735a1d..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/pom.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - 4.0.0 - org.openapitools - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../../applications/mp/pom.xml - - openapi-mp-server - openapi-java-server - This is a sample for Helidon Quickstart project. - 1.0.0 - jar - - - 0.2.3 - 6.2.1 - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.cdi - helidon-microprofile-cdi - - - jakarta.enterprise - jakarta.enterprise.cdi-api - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.openapitools - jackson-databind-nullable - ${version.jackson.databind.nullable} - - - org.glassfish.jersey.media - jersey-media-json-jackson - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/META-INF/openapi.yml - java-helidon-server - mp - ${project.basedir} - - false - - - - - - - - - - diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/JavaTimeFormatter.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/JavaTimeFormatter.java deleted file mode 100644 index 2cbdf89970c..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/JavaTimeFormatter.java +++ /dev/null @@ -1,74 +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 org.openapitools.server; - -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; - -/** - * Class that add parsing/formatting support for Java 8+ {@code OffsetDateTime} class. - * It's generated for java clients when {@code AbstractJavaCodegen#dateLibrary} specified as {@code java8}. - */ -@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaHelidonServerCodegen", date = "2022-10-25T09:58" - + ":58.439110277+02:00[Europe/Prague]") -public class JavaTimeFormatter { - - private DateTimeFormatter offsetDateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; - - /** - * Get the date format used to parse/format {@code OffsetDateTime} parameters. - * - * @return DateTimeFormatter - */ - public DateTimeFormatter getOffsetDateTimeFormatter() { - return offsetDateTimeFormatter; - } - - /** - * Set the date format used to parse/format {@code OffsetDateTime} parameters. - * - * @param offsetDateTimeFormatter {@code DateTimeFormatter} - */ - public void setOffsetDateTimeFormatter(DateTimeFormatter offsetDateTimeFormatter) { - this.offsetDateTimeFormatter = offsetDateTimeFormatter; - } - - /** - * Parse the given string into {@code OffsetDateTime} object. - * - * @param str String - * @return {@code OffsetDateTime} - */ - public OffsetDateTime parseOffsetDateTime(String str) { - try { - return OffsetDateTime.parse(str, offsetDateTimeFormatter); - } catch (DateTimeParseException e) { - throw new RuntimeException(e); - } - } - - /** - * Format the given {@code OffsetDateTime} object into string. - * - * @param offsetDateTime {@code OffsetDateTime} - * @return {@code OffsetDateTime} in string format - */ - public String formatOffsetDateTime(OffsetDateTime offsetDateTime) { - return offsetDateTimeFormatter.format(offsetDateTime); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java deleted file mode 100644 index 47151e1a7fe..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openapitools.server; - -import java.text.DateFormat; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.TimeZone; - -import com.fasterxml.jackson.databind.util.StdDateFormat; - -public class RFC3339DateFormat extends DateFormat { - private static final long serialVersionUID = 1L; - private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); - - private final StdDateFormat fmt = new StdDateFormat() - .withTimeZone(TIMEZONE_Z) - .withColonInTimeZone(true); - - public RFC3339DateFormat() { - this.calendar = new GregorianCalendar(); - } - - @Override - public Date parse(String source, ParsePosition pos) { - return fmt.parse(source, pos); - } - - @Override - public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { - return fmt.format(date, toAppendTo, fieldPosition); - } - - @Override - public Object clone() { - return this; - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RestApplication.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RestApplication.java deleted file mode 100644 index b9e26cecbae..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/RestApplication.java +++ /dev/null @@ -1,27 +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 org.openapitools.server; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -@ApplicationScoped -@ApplicationPath("") -public class RestApplication extends Application { - -} diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageService.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageService.java deleted file mode 100644 index efefe7e97b4..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageService.java +++ /dev/null @@ -1,47 +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 org.openapitools.server.api; - -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import org.openapitools.server.model.Message; - -@Path("/greet") -@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaHelidonServerCodegen", date = "2022-10-25T09:58" - + ":58.439110277+02:00[Europe/Prague]") -public interface MessageService { - - @GET - @Produces({"application/json"}) - Message getDefaultMessage(); - - @GET - @Path("/{name}") - @Produces({"application/json"}) - Message getMessage(@PathParam("name") String name); - - @PUT - @Path("/greeting") - @Consumes({"application/json"}) - void updateGreeting(@Valid @NotNull Message message); -} diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java deleted file mode 100644 index 0bd8722d3ed..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java +++ /dev/null @@ -1,72 +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 org.openapitools.server.api; - -import java.util.concurrent.atomic.AtomicReference; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Response; -import org.openapitools.server.model.Message; - -/** - * MessageService implementation. - */ -@ApplicationScoped -@Path("/greet") -@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaHelidonServerCodegen", date = "2022-10-25T09:58" - + ":58.439110277+02:00[Europe/Prague]") -public class MessageServiceImpl implements MessageService { - - private final AtomicReference defaultMessage = new AtomicReference<>(); - - public MessageServiceImpl() { - Message message = new Message(); - message.setMessage("World"); - message.setGreeting("Hello"); - defaultMessage.set(message); - } - - @GET - @Produces({"application/json"}) - public Message getDefaultMessage() { - return defaultMessage.get(); - } - - @GET - @Path("/{name}") - @Produces({"application/json"}) - public Message getMessage(@PathParam("name") String name) { - Message result = new Message(); - return result.message(name).greeting(defaultMessage.get().getGreeting()); - } - - @PUT - @Path("/greeting") - @Consumes({"application/json"}) - public void updateGreeting(@Valid @NotNull Message message) { - defaultMessage.set(message); - Response.status(Response.Status.NO_CONTENT).build(); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/package-info.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/package-info.java deleted file mode 100644 index b74575ed753..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/api/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. - */ - -/** - * Api package. - */ -package org.openapitools.server.api; diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/Message.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/Message.java deleted file mode 100644 index 2c44c9910e2..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/Message.java +++ /dev/null @@ -1,95 +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 org.openapitools.server.model; - -/** - * An message for the user - **/ -public class Message { - - private String message; - - private String greeting; - - /** - * Get message - * - * @return message - **/ - public String getMessage() { - return message; - } - - /** - * Set message - **/ - public void setMessage(String message) { - this.message = message; - } - - public Message message(String message) { - this.message = message; - return this; - } - - /** - * Get greeting - * - * @return greeting - **/ - public String getGreeting() { - return greeting; - } - - /** - * Set greeting - **/ - public void setGreeting(String greeting) { - this.greeting = greeting; - } - - public Message greeting(String greeting) { - this.greeting = greeting; - return this; - } - - - /** - * Create a string representation of this pojo. - **/ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Message {\n"); - - sb.append(" message: ").append(toIndentedString(message)).append("\n"); - sb.append(" greeting: ").append(toIndentedString(greeting)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private static String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/package-info.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/package-info.java deleted file mode 100644 index 416edf3da68..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/model/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. - */ - -/** - * Models. - */ -package org.openapitools.server.model; diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/package-info.java b/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/package-info.java deleted file mode 100644 index 5a343d932a2..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/java/org/openapitools/server/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon MP server. - */ -package org.openapitools.server; diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/beans.xml b/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4e2030d4e9a..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/microprofile-config.properties b/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 3bed5e9311c..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Microprofile server properties - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/openapi.yml b/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/openapi.yml deleted file mode 100644 index c2b85c23770..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/META-INF/openapi.yml +++ /dev/null @@ -1,104 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -openapi: 3.0.0 -info: - description: This is a sample for Helidon Quickstart project. - license: - name: Apache-2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - title: OpenAPI Helidon Quickstart - version: 1.0.0 -servers: -- url: http://localhost:8080 -tags: -- name: message -paths: - /greet: - get: - operationId: getDefaultMessage - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: successful operation - summary: Return a worldly greeting message. - tags: - - message - x-accepts: application/json - /greet/greeting: - put: - operationId: updateGreeting - requestBody: - $ref: '#/components/requestBodies/Message' - responses: - "200": - description: successful operation - "400": - description: No greeting provided - summary: Set the greeting to use in future messages. - tags: - - message - x-content-type: application/json - x-accepts: application/json - /greet/{name}: - get: - operationId: getMessage - parameters: - - description: the name to greet - explode: false - in: path - name: name - required: true - schema: - type: string - style: simple - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: successful operation - summary: Return a greeting message using the name that was provided. - tags: - - message - x-accepts: application/json -components: - requestBodies: - Message: - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: Message for the user - required: true - schemas: - Message: - description: An message for the user - example: - greeting: greeting - message: message - properties: - message: - format: int64 - type: string - greeting: - format: int64 - type: string - type: object diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/logging.properties b/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/logging.properties deleted file mode 100644 index d73eb5b6607..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/openapi-tools/quickstart-mp/mp-server/src/test/java/org/openapitools/server/model/MessageTest.java b/examples/openapi-tools/quickstart-mp/mp-server/src/test/java/org/openapitools/server/model/MessageTest.java deleted file mode 100644 index ca21dbe79bc..00000000000 --- a/examples/openapi-tools/quickstart-mp/mp-server/src/test/java/org/openapitools/server/model/MessageTest.java +++ /dev/null @@ -1,52 +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 org.openapitools.server.model; - -import org.junit.jupiter.api.Test; - - -/** - * Model tests for Message - */ -public class MessageTest { - private final Message model = new Message(); - - /** - * Model tests for Message - */ - @Test - public void testMessage() { - // TODO: test Message - } - - /** - * Test the property 'message' - */ - @Test - public void messageTest() { - // TODO: test message - } - - /** - * Test the property 'greeting' - */ - @Test - public void greetingTest() { - // TODO: test greeting - } - -} diff --git a/examples/openapi-tools/quickstart-mp/pom.xml b/examples/openapi-tools/quickstart-mp/pom.xml deleted file mode 100644 index 444a7811a7a..00000000000 --- a/examples/openapi-tools/quickstart-mp/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.openapi.tools - helidon-examples-openapi-tools-project - 3.2.7-SNAPSHOT - - pom - helidon-examples-openapi-tools-quickstart-mp - Helidon OpenApi Tools Example for Quickstart MP - - - Example of usage OpenApi Tools for Helidon Quickstart MP server and client - - - - mp-server - mp-client - - diff --git a/examples/openapi-tools/quickstart-se/README.md b/examples/openapi-tools/quickstart-se/README.md deleted file mode 100644 index 2aca6bf287f..00000000000 --- a/examples/openapi-tools/quickstart-se/README.md +++ /dev/null @@ -1,387 +0,0 @@ -# Helidon OpenAPI Generator example for Helidon SE server and client - -The goal of this example is to show how a user can easily create a Helidon SE server or client from an OpenAPI document using OpenAPI Generator. - -Here we will show the steps that a user has to do to create Helidon SE server and client using OpenAPI Generator and what has to be done to make the generated server and client fully functional. - -For generation of our projects we will use `openapi-generator-cli.jar` that can be downloaded from the maven repository (instructions and other options can be found [here](https://openapi-generator.tech/docs/installation)) and OpenAPI document `quickstart.yaml` that can be found next to this `README.md`. - -## Build, prepare and run the Helidon SE server - -To generate Helidon SE server at first we create `se-server` folder and then inside it we run the following command where `path-to-generator` is the directory where you downloaded the generator CLI JAR file and `path-to-openapi-doc` is the folder where `quickstart.yaml` is located: -```bash -java -jar path-to-generator/openapi-generator-cli.jar \ - generate \ - -g java-helidon-server \ - --library se \ - -i path-to-openapi-doc/quickstart.yaml -``` - -When this command finishes its work in the folder `se-server` we will find the generated project where the most interesting parts are located inside `api` and `model` packages. -The package `api` contains interfaces that represent endpoints for our server and implementations with stubs for them. -These implementations we need to change to implement our business logic. -The package `model` contains classes that represent transport objects that will be used by our endpoints to receive requests and send responses. - -Let's change a little class `MessageServiceImpl` for our example : -1) Add field that will contain default message for our endpoints : -```java - private final AtomicReference defaultMessage = new AtomicReference<>(); -``` -2) Add default constructor to the class : -```java - public MessageServiceImpl() { - Message message = new Message(); - message.setMessage("World"); - message.setGreeting("Hello"); - defaultMessage.set(message); - } -``` -3) Replace implementation of the method `public void getDefaultMessage(ServerRequest request, ServerResponse response)` by this: -```java - response.send(defaultMessage.get()); -``` -4) Replace implementation of the method `public void getMessage(ServerRequest request, ServerResponse response)` by this: -```java - String name = request.path().param("name"); - Message result = new Message(); - result.setMessage(name); - result.setGreeting(defaultMessage.get().getGreeting()); - response.send(result); -``` -5) Replace implementation of the method `public void updateGreeting(ServerRequest request, ServerResponse response, Message message)` by this: -```java - if (message.getGreeting() == null) { - Message jsonError = new Message(); - jsonError.setMessage("No greeting provided"); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonError); - return; - } - defaultMessage.set(message); - response.status(Http.Status.NO_CONTENT_204).send(); -``` - -To run the application : - -With JDK17+ -```bash -mvn package -java -jar target/openapi-java-server.jar -``` - -To check that server works as expected run the following `curl` commands : - -``` -curl -X GET http://localhost:8080/greet -{"message":"World","greeting":"Hello"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Joe","greeting":"Hello"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola", "message":"Lisa"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet -{"message":"Lisa","greeting":"Hola"} -``` - -## Build, prepare and run the Helidon SE client - -The second part of this example is generating Helidon Webclient that will communicate with the server that we have just created. - -To generate Helidon SE Webclient at first we create `se-client` folder and then inside it we run the following command where `path-to-generator` is the directory where you downloaded the generator CLI JAR file and `path-to-openapi-doc` is the folder where `quickstart.yaml` is located: -```bash -java -jar path-to-generator/openapi-generator-cli.jar \ - generate \ - -g java-helidon-client \ - --library se \ - -i path-to-openapi-doc/quickstart.yaml -``` - -When this command finishes its work in the folder `se-client` we will find the generated project. -As with the server project the most interesting parts are located inside `api` and `model` packages and `ApiClient` class. -The package `api` contains interfaces that represent endpoints to our server and implementations for them. -The package `model` contains classes that represent transport objects that will be used to communicate with the server. -`ApiClient` class represents configuration and utility class for `WebClient` that is used to connect to our server. - -You can use the generated SE client artifact in either of two ways: - - - as a library - One or more other client projects can depend on the client artifact and use its generated classes. - - as a client program itself - Add some code to the generated project to make it a client program and not just a library. - -This example illustrates the second approach. We create a second server (at port 8081) which accepts greeting requests and, acting as a client, forwards them to the first service and returns the responses from the first service as its own. - -To make our client application fully functional let's add some classes, dependencies and files to the project. - -1) Add to the `pom.xml` : -```xml - - org.openapitools.client.Main - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - -``` - -2) Let's add a class `MessageService` to the `api` package that will use `MessageApi` and `ApiClient` to interact with the server : -```java -package org.openapitools.client.api; - -import io.helidon.common.http.Http; -import io.helidon.webserver.Handler; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; -import org.openapitools.client.ApiClient; -import org.openapitools.client.model.Message; - -public class MessageService implements Service { - - private final MessageApi api; - - public MessageService() { - ApiClient apiClient = ApiClient.builder().build(); - api = MessageApiImpl.create(apiClient); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules.get("/greet", this::getDefaultMessage); - rules.get("/greet/{name}", this::getMessage); - rules.put("/greet/greeting", Handler.create(Message.class, this::updateGreeting)); - } - - /** - * GET /greet : Return a worldly greeting message.. - * - * @param request the server request - * @param response the server response - */ - public void getDefaultMessage(ServerRequest request, ServerResponse response) { - api.getDefaultMessage() - .webClientResponse() - .flatMapSingle(serverResponse -> serverResponse.content().as(Message.class)) - .thenAccept(response::send); - } - - /** - * GET /greet/{name} : Return a greeting message using the name that was provided.. - * - * @param request the server request - * @param response the server response - */ - public void getMessage(ServerRequest request, ServerResponse response) { - String name = request.path().param("name"); - api.getMessage(name) - .webClientResponse() - .flatMapSingle(serverResponse -> serverResponse.content().as(Message.class)) - .thenAccept(response::send); - } - - /** - * PUT /greet/greeting : Set the greeting to use in future messages.. - * - * @param request the server request - * @param response the server response - * @param message Message for the user - */ - public void updateGreeting(ServerRequest request, ServerResponse response, Message message) { - api.updateGreeting(message) - .webClientResponse() - .thenAccept(content -> response.status(Http.Status.NO_CONTENT_204).send()); - } -} -``` - -3) Add class `Main` that will be the main class for our client : -```java -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JacksonSupport.create()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:8081"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - return Routing.builder() - .register("/", new MessageService()) - .build(); - } -} -``` - -4) Create the directory `src/main/resources/`. Create `application.yaml` in that directory with the following content: -```yaml -server: - port: 8081 - host: localhost -``` - -To run the application : - -With JDK17+ -```bash -mvn package -java -jar target/openapi-java-client.jar -``` - -To check that client works as expected and process all the request using our server run the following `curl` commands : - -``` -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola", "message":"Lisa"}' http://localhost:8081/greet/greeting - -curl -X GET http://localhost:8081/greet -{"message":"Lisa","greeting":"Hola"} - -curl -X GET http://localhost:8081/greet/Joe -{"message":"Joe","greeting":"Hola"} -``` - -## Update applications - -To keep the server and the client up to date according to the OpenApi document, we can use the maven plugin. - -Add these lines to the `pom.xml` of our server : -```xml - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/META-INF/openapi.yml - java-helidon-server - se - ${project.basedir} - - false - - - - - - - - - -``` - -For the client application : -1) Copy the OpenApi document `path-to-openapi-doc/quickstart.yaml` to the folder `resources` and rename it to `openapi.yaml`. -2) Add these lines to the `pom.xml` of our client : -```xml - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/openapi.yml - java-helidon-client - se - ${project.basedir} - - false - - - - - - - - - -``` - -Also add the following to the `` in the `pom.xml` file: -```xml -6.2.1 -``` - -The version `6.2.1` was the first version where Helidon generators were added, so if more modern versions of this plugin are exist you can choose one of them. - -To run the generator during your build, invoke the profile: `mvn clean package -P openapi`. - -It should also be added that the `fullProject` option was used in the plugin configuration. -If it set to true, it will generate all files; if set to false, it will only generate API files. -If unspecified, the behavior depends on whether a project exists or not: if it does not, same as true; if it does, same as false. -So keep in mind that regenerating will overwrite your customized `MessageService` or `Message` files and you will need to add the customization again after regenerating. -Note that test files are never overwritten. diff --git a/examples/openapi-tools/quickstart-se/pom.xml b/examples/openapi-tools/quickstart-se/pom.xml deleted file mode 100644 index 3843ad516dd..00000000000 --- a/examples/openapi-tools/quickstart-se/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.openapi.tools - helidon-examples-openapi-tools-project - 3.2.7-SNAPSHOT - - pom - helidon-examples-openapi-tools-quickstart-se - Helidon OpenApi Tools Example for Quickstart SE - - - Example of usage OpenApi Tools for Helidon Quickstart SE server and client - - - - se-server - se-client - - diff --git a/examples/openapi-tools/quickstart-se/se-client/README.md b/examples/openapi-tools/quickstart-se/se-client/README.md deleted file mode 100644 index a3edb6fbcdf..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# OpenAPI Helidon Quickstart - -This is a sample for Helidon Quickstart project. - - -## Overview -This project was generated using the Helidon OpenAPI Generator. - -The generated classes use the programming model from the Helidon WebClient implementation, primarily the `WebClient` interface and its -`WebClient.Builder` class. Refer to the Helidon WebClient documentation for complete information about them. - -## Using the Generated Classes and Interfaces -The generated `ApiClient` class wraps a `WebClient` instance. Similarly, the `ApiClient.Builder` class wraps the `WebClient.Builder` class. - -The generated `xxxApi` interfaces and `xxxApiImpl` classes make it very simple for your code to send requests (with input parameters) to the remote service which the OpenAPI document describes and to process the response (with output values) from the remote service. - -To use the generated API, your code performs the following steps. - -1. Create an instance of the `ApiClient` using its `Builder`. -2. Create an instance of a `xxxApi` it wants to access, typically by invoking `xxxApiImpl.create(ApiClient)` and passing the `ApiClient` instance just created. -3. Invoke any of the `public` methods on the `xxxApi` instance, passing the input parameters and saving the returned `Single` object. -4. Invoke methods on the returned `Single` to process the response and any output from it. - -Browse the methods and JavaDoc on the generated classes for more information. diff --git a/examples/openapi-tools/quickstart-se/se-client/docs/Message.md b/examples/openapi-tools/quickstart-se/se-client/docs/Message.md deleted file mode 100644 index df42a18ce87..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/docs/Message.md +++ /dev/null @@ -1,15 +0,0 @@ - - -# Message - -An message for the user - -## Properties - -| Name | Type | Description | Notes | -|------------ | ------------- | ------------- | -------------| -|**message** | **String** | | [optional] | -|**greeting** | **String** | | [optional] | - - - diff --git a/examples/openapi-tools/quickstart-se/se-client/docs/MessageApi.md b/examples/openapi-tools/quickstart-se/se-client/docs/MessageApi.md deleted file mode 100644 index 094434a3163..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/docs/MessageApi.md +++ /dev/null @@ -1,199 +0,0 @@ -# MessageApi - -All URIs are relative to *http://localhost:8080* - -| Method | HTTP request | Description | -|------------- | ------------- | -------------| -| [**getDefaultMessage**](MessageApi.md#getDefaultMessage) | **GET** /greet | Return a worldly greeting message. | -| [**getMessage**](MessageApi.md#getMessage) | **GET** /greet/{name} | Return a greeting message using the name that was provided. | -| [**updateGreeting**](MessageApi.md#updateGreeting) | **PUT** /greet/greeting | Set the greeting to use in future messages. | - - - -## getDefaultMessage - -> Message getDefaultMessage() - -Return a worldly greeting message. - -### Example - -```java -// Import classes: -import org.openapitools.client.ApiClient; -import org.openapitools.client.ApiException; -import org.openapitools.client.Configuration; -import org.openapitools.client.models.*; -import org.openapitools.client.api.MessageApi; - -public class Example { - public static void main(String[] args) { - ApiClient defaultClient = Configuration.getDefaultApiClient(); - defaultClient.setBasePath("http://localhost:8080"); - - MessageApi apiInstance = new MessageApi(defaultClient); - try { - Message result = apiInstance.getDefaultMessage(); - System.out.println(result); - } catch (ApiException e) { - System.err.println("Exception when calling MessageApi#getDefaultMessage"); - System.err.println("Status code: " + e.getCode()); - System.err.println("Reason: " + e.getResponseBody()); - System.err.println("Response headers: " + e.getResponseHeaders()); - e.printStackTrace(); - } - } -} -``` - -### Parameters - -This endpoint does not need any parameter. - -### Return type - -[**Message**](Message.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: application/json - - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -| **200** | successful operation | - | - - -## getMessage - -> Message getMessage(name) - -Return a greeting message using the name that was provided. - -### Example - -```java -// Import classes: -import org.openapitools.client.ApiClient; -import org.openapitools.client.ApiException; -import org.openapitools.client.Configuration; -import org.openapitools.client.models.*; -import org.openapitools.client.api.MessageApi; - -public class Example { - public static void main(String[] args) { - ApiClient defaultClient = Configuration.getDefaultApiClient(); - defaultClient.setBasePath("http://localhost:8080"); - - MessageApi apiInstance = new MessageApi(defaultClient); - String name = "name_example"; // String | the name to greet - try { - Message result = apiInstance.getMessage(name); - System.out.println(result); - } catch (ApiException e) { - System.err.println("Exception when calling MessageApi#getMessage"); - System.err.println("Status code: " + e.getCode()); - System.err.println("Reason: " + e.getResponseBody()); - System.err.println("Response headers: " + e.getResponseHeaders()); - e.printStackTrace(); - } - } -} -``` - -### Parameters - - -| Name | Type | Description | Notes | -|------------- | ------------- | ------------- | -------------| -| **name** | **String**| the name to greet | | - -### Return type - -[**Message**](Message.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: application/json - - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -| **200** | successful operation | - | - - -## updateGreeting - -> updateGreeting(message) - -Set the greeting to use in future messages. - -### Example - -```java -// Import classes: -import org.openapitools.client.ApiClient; -import org.openapitools.client.ApiException; -import org.openapitools.client.Configuration; -import org.openapitools.client.models.*; -import org.openapitools.client.api.MessageApi; - -public class Example { - public static void main(String[] args) { - ApiClient defaultClient = Configuration.getDefaultApiClient(); - defaultClient.setBasePath("http://localhost:8080"); - - MessageApi apiInstance = new MessageApi(defaultClient); - Message message = new Message(); // Message | Message for the user - try { - apiInstance.updateGreeting(message); - } catch (ApiException e) { - System.err.println("Exception when calling MessageApi#updateGreeting"); - System.err.println("Status code: " + e.getCode()); - System.err.println("Reason: " + e.getResponseBody()); - System.err.println("Response headers: " + e.getResponseHeaders()); - e.printStackTrace(); - } - } -} -``` - -### Parameters - - -| Name | Type | Description | Notes | -|------------- | ------------- | ------------- | -------------| -| **message** | [**Message**](Message.md)| Message for the user | | - -### Return type - -null (empty response body) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: application/json -- **Accept**: Not defined - - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -| **200** | successful operation | - | -| **400** | No greeting provided | - | - diff --git a/examples/openapi-tools/quickstart-se/se-client/pom.xml b/examples/openapi-tools/quickstart-se/se-client/pom.xml deleted file mode 100644 index 1e01c5aa28e..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/pom.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - 4.0.0 - org.openapitools - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - openapi-se-client - openapi-java-client - This is a sample for Helidon Quickstart project. - 1.0.0 - jar - - - org.openapitools.client.Main - 6.2.1 - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webclient - helidon-webclient - - - io.helidon.config - helidon-config - - - jakarta.json - jakarta.json-api - - - io.helidon.media - helidon-media-jackson - - - org.glassfish.jersey.media - jersey-media-json-jackson - - - org.openapitools - jackson-databind-nullable - 0.2.2 - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/META-INF/openapi.yml - java-helidon-client - se - ${project.basedir} - - false - - - - - - - - - - diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiClient.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiClient.java deleted file mode 100644 index 349b3690219..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiClient.java +++ /dev/null @@ -1,242 +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 org.openapitools.client; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import io.helidon.config.Config; -import io.helidon.media.jackson.JacksonSupport; -import io.helidon.webclient.WebClient; - -import java.net.URLEncoder; -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.StringJoiner; -import java.util.stream.Collectors; - -import static java.nio.charset.StandardCharsets.UTF_8; - -/** - * Configuration and utility class for API clients. - *

- * Use the {@link ApiClient.Builder} class to prepare and ultimately create the {@code ApiClient} instance. - *

- */ -public class ApiClient { - - private final WebClient webClient; - - /** - * @return a {@code Builder} for an {@code ApiClient} - */ - public static ApiClient.Builder builder() { - return new Builder(); - } - - /** - * URL encode a string in the UTF-8 encoding. - * - * @param s String to encode. - * @return URL-encoded representation of the input string. - */ - public static String urlEncode(String s) { - return URLEncoder.encode(s, UTF_8); - } - - /** - * Convert a URL query name/value parameter to a list of encoded {@link Pair} - * objects. - * - *

The value can be null, in which case an empty list is returned.

- * - * @param name The query name parameter. - * @param value The query value, which may not be a collection but may be - * null. - * @return A singleton list of the {@link Pair} objects representing the input - * parameters, which is encoded for use in a URL. If the value is null, an - * empty list is returned. - */ - public static List parameterToPairs(String name, Object value) { - if (name == null || name.isEmpty() || value == null) { - return Collections.emptyList(); - } - return Collections.singletonList(new Pair(urlEncode(name), urlEncode(valueToString(value)))); - } - - /** - * Convert a URL query name/collection parameter to a list of encoded - * {@link Pair} objects. - * - * @param collectionFormat The swagger collectionFormat string (csv, tsv, etc). - * @param name The query name parameter. - * @param values A collection of values for the given query name, which may be - * null. - * @return A list of {@link Pair} objects representing the input parameters, - * which is encoded for use in a URL. If the values collection is null, an - * empty list is returned. - */ - public static List parameterToPairs( - String collectionFormat, String name, Collection values) { - if (name == null || name.isEmpty() || values == null || values.isEmpty()) { - return Collections.emptyList(); - } - - // get the collection format (default: csv) - String format = collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat; - - // create the params based on the collection format - if ("multi".equals(format)) { - return values.stream() - .map(value -> new Pair(urlEncode(name), urlEncode(valueToString(value)))) - .collect(Collectors.toList()); - } - - String delimiter; - switch (format) { - case "csv": - delimiter = urlEncode(","); - break; - case "ssv": - delimiter = urlEncode(" "); - break; - case "tsv": - delimiter = urlEncode("\t"); - break; - case "pipes": - delimiter = urlEncode("|"); - break; - default: - throw new IllegalArgumentException("Illegal collection format: " + collectionFormat); - } - - StringJoiner joiner = new StringJoiner(delimiter); - for (Object value : values) { - joiner.add(urlEncode(valueToString(value))); - } - - return Collections.singletonList(new Pair(urlEncode(name), joiner.toString())); - } - - private ApiClient(Builder builder) { - webClient = builder.webClientBuilder().build(); - } - - /** - * Get the {@link WebClient} prepared by the builder of this {@code ApiClient}. - * - * @return the WebClient - */ - public WebClient webClient() { - return webClient; - } - - private static String valueToString(Object value) { - if (value == null) { - return ""; - } - if (value instanceof OffsetDateTime) { - return ((OffsetDateTime) value).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); - } - return value.toString(); - } - - /** - * Builder for creating a new {@code ApiClient} instance. - * - *

- * The builder accepts a {@link WebClient.Builder} via the {@code webClientBuilder} method but will provide a default one - * using available configuration (the {@code client} node) and the base URI set in the OpenAPI document. - *

- */ - public static class Builder { - - private WebClient.Builder webClientBuilder; - private Config clientConfig; - private ObjectMapper objectMapper; - - public ApiClient build() { - return new ApiClient(this); - } - - /** - * Sets the {@code WebClient.Builder} which the {@code ApiClient.Builder} uses. Any previous setting is discarded. - * - * @param webClientBuilder the {@code WebClient.Builder} to be used going forward - * @return the updated builder - */ - public Builder webClientBuilder(WebClient.Builder webClientBuilder) { - this.webClientBuilder = webClientBuilder; - return this; - } - - /** - * Sets the client {@code Config} which the {@code ApiClient.Builder} uses in preparing a default {@code WebClient - * .Builder}. - * The builder ignores this setting if you provide your own {@code WebClient.Builder} by invoking the - * {@code webClientBuilder} method. - * - * @param clientConfig the {@code Config} node containing client settings - * @return the updated builder - */ - public Builder clientConfig(Config clientConfig) { - this.clientConfig = clientConfig; - return this; - } - - /** - * @return the previously-stored web client builder or, if none, a default one using the provided or defaulted - * client configuration - */ - public WebClient.Builder webClientBuilder() { - if (webClientBuilder == null) { - webClientBuilder = defaultWebClientBuilder(); - } - return webClientBuilder; - } - - /** - * Stores the Jackson {@code ObjectMapper} the builder uses in preparing the {@code WebClient}. - * - * @param objectMapper the Jackson object mapper to use in all API invocations via the built {@code ApiClient} - * @return the updated builder - */ - public Builder objectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - private WebClient.Builder defaultWebClientBuilder() { - WebClient.Builder defaultWebClientBuilder = WebClient.builder() - .baseUri("http://localhost:8080") - .config(clientConfig()); - defaultWebClientBuilder.addMediaSupport(objectMapper == null - ? JacksonSupport.create() - : JacksonSupport.create(objectMapper)); - return defaultWebClientBuilder; - } - - private Config clientConfig() { - if (clientConfig == null) { - clientConfig = Config.create().get("client"); - } - return clientConfig; - } - } -} \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponse.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponse.java deleted file mode 100644 index 9c790f94db8..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponse.java +++ /dev/null @@ -1,47 +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 org.openapitools.client; - -import java.util.concurrent.ExecutionException; - -import io.helidon.common.GenericType; -import io.helidon.common.reactive.Single; -import io.helidon.webclient.WebClientResponse; - -/** - * Generic-typed response. - *

- * Return type for generated API methods. - * - * @param type of the return value from the generated API method - */ -public interface ApiResponse { - - static ApiResponse create(GenericType responseType, Single webClientResponse) { - return new ApiResponseBase<>(responseType, webClientResponse); - } - - /** - * @returns reactive access to the {@link WebClientResponse} describing the response from the server - */ - Single webClientResponse(); - - /** - * @return reactive access to the value returned in the response from the server - */ - Single result() throws ExecutionException, InterruptedException; -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponseBase.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponseBase.java deleted file mode 100644 index 0abd1d4bf10..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/ApiResponseBase.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 org.openapitools.client; - -import java.util.concurrent.ExecutionException; - -import io.helidon.common.GenericType; -import io.helidon.common.reactive.Single; -import io.helidon.webclient.WebClientResponse; - -/** - * Implementation of a generic-typed response. - * - * @param type of the return value from the generated API method - */ -class ApiResponseBase implements ApiResponse { - - private final Single webClientResponse; - private final GenericType responseType; - - protected ApiResponseBase(GenericType responseType, Single webClientResponse) { - this.webClientResponse = webClientResponse; - this.responseType = responseType; - } - - @Override - public Single webClientResponse() { - return webClientResponse; - } - - @Override - public Single result() throws ExecutionException, InterruptedException { - return webClientResponse.get().content().as(responseType); - } -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Main.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Main.java deleted file mode 100644 index 53a8cc83297..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Main.java +++ /dev/null @@ -1,90 +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 org.openapitools.client; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.media.jackson.JacksonSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import org.openapitools.client.api.MessageService; - -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JacksonSupport.create()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:8081"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link Routing}. - * - * @param config configuration of this server - * @return routing configured with JSON support, a health check, and a service - */ - private static Routing createRouting(Config config) { - - return Routing.builder() - .register("/", new MessageService()) - .build(); - } -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Pair.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Pair.java deleted file mode 100644 index c203fc8c856..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/Pair.java +++ /dev/null @@ -1,60 +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 org.openapitools.client; - -public class Pair { - private String name = ""; - private String value = ""; - - public Pair(String name, String value) { - setName(name); - setValue(value); - } - - private void setName(String name) { - if (!isValidString(name)) { - return; - } - - this.name = name; - } - - private void setValue(String value) { - if (!isValidString(value)) { - return; - } - - this.value = value; - } - - public String getName() { - return this.name; - } - - public String getValue() { - return this.value; - } - - private boolean isValidString(String arg) { - if (arg == null) { - return false; - } - - return true; - } -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java deleted file mode 100644 index 7f0baf5a1f3..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/RFC3339DateFormat.java +++ /dev/null @@ -1,61 +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 org.openapitools.client; - -import com.fasterxml.jackson.databind.util.StdDateFormat; - -import java.text.DateFormat; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.util.Date; -import java.text.DecimalFormat; -import java.util.GregorianCalendar; -import java.util.TimeZone; - -public class RFC3339DateFormat extends DateFormat { - private static final long serialVersionUID = 1L; - private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); - - private final StdDateFormat fmt = new StdDateFormat() - .withTimeZone(TIMEZONE_Z) - .withColonInTimeZone(true); - - public RFC3339DateFormat() { - this.calendar = new GregorianCalendar(); - this.numberFormat = new DecimalFormat(); - } - - @Override - public Date parse(String source) { - return parse(source, new ParsePosition(0)); - } - - @Override - public Date parse(String source, ParsePosition pos) { - return fmt.parse(source, pos); - } - - @Override - public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { - return fmt.format(date, toAppendTo, fieldPosition); - } - - @Override - public Object clone() { - return super.clone(); - } -} \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApi.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApi.java deleted file mode 100644 index 6f7b88f8c7d..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApi.java +++ /dev/null @@ -1,52 +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 org.openapitools.client.api; - -import org.openapitools.client.ApiResponse; -import org.openapitools.client.model.Message; - -/** - * OpenAPI Helidon Quickstart - * - *

This is a sample for Helidon Quickstart project. - */ -public interface MessageApi { - - /** - * Return a worldly greeting message. - * - * @return {@code ApiResponse} - */ - ApiResponse getDefaultMessage(); - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet (required) - * @return {@code ApiResponse} - */ - ApiResponse getMessage(String name); - - /** - * Set the greeting to use in future messages. - * - * @param message Message for the user (required) - * @return {@code ApiResponse} - */ - ApiResponse updateGreeting(Message message); - -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApiImpl.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApiImpl.java deleted file mode 100644 index 1e4864a6c09..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageApiImpl.java +++ /dev/null @@ -1,166 +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 org.openapitools.client.api; - -import java.util.Objects; -import org.openapitools.client.ApiResponse; - -import io.helidon.common.GenericType; -import io.helidon.common.http.MediaType; -import io.helidon.common.reactive.Single; -import io.helidon.webclient.WebClientRequestBuilder; -import io.helidon.webclient.WebClientResponse; - -import org.openapitools.client.ApiClient; -import org.openapitools.client.model.Message; - -/** - * OpenAPI Helidon Quickstart - * - *

This is a sample for Helidon Quickstart project. - */ -public class MessageApiImpl implements MessageApi { - - private final ApiClient apiClient; - - protected static final GenericType RESPONSE_TYPE_getDefaultMessage = ResponseType.create(Message.class); - protected static final GenericType RESPONSE_TYPE_getMessage = ResponseType.create(Message.class); - protected static final GenericType RESPONSE_TYPE_updateGreeting = ResponseType.create(Void.class); - - /** - * Creates a new instance of MessageApiImpl initialized with the specified {@link ApiClient}. - * - */ - public static MessageApiImpl create(ApiClient apiClient) { - return new MessageApiImpl(apiClient); - } - - protected MessageApiImpl(ApiClient apiClient) { - this.apiClient = apiClient; - } - - @Override - public ApiResponse getDefaultMessage() { - WebClientRequestBuilder webClientRequestBuilder = getDefaultMessageRequestBuilder(); - return getDefaultMessageSubmit(webClientRequestBuilder); - } - - /** - * Creates a {@code WebClientRequestBuilder} for the getDefaultMessage operation. - * Optional customization point for subclasses. - * - * @return WebClientRequestBuilder for getDefaultMessage - */ - protected WebClientRequestBuilder getDefaultMessageRequestBuilder() { - WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient() - .method("GET"); - - webClientRequestBuilder.path("/greet"); - webClientRequestBuilder.accept(MediaType.APPLICATION_JSON); - - return webClientRequestBuilder; - } - - /** - * Initiates the request for the getDefaultMessage operation. - * Optional customization point for subclasses. - * - * @param webClientRequestBuilder the request builder to use for submitting the request - * @return {@code ApiResponse} for the submitted request - */ - protected ApiResponse getDefaultMessageSubmit(WebClientRequestBuilder webClientRequestBuilder) { - Single webClientResponse = webClientRequestBuilder.submit(); - return ApiResponse.create(RESPONSE_TYPE_getDefaultMessage, webClientResponse); - } - - @Override - public ApiResponse getMessage(String name) { - Objects.requireNonNull(name, "Required parameter 'name' not specified"); - WebClientRequestBuilder webClientRequestBuilder = getMessageRequestBuilder(name); - return getMessageSubmit(webClientRequestBuilder, name); - } - - /** - * Creates a {@code WebClientRequestBuilder} for the getMessage operation. - * Optional customization point for subclasses. - * - * @param name the name to greet (required) - * @return WebClientRequestBuilder for getMessage - */ - protected WebClientRequestBuilder getMessageRequestBuilder(String name) { - WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient() - .method("GET"); - - String path = "/greet/{name}" - .replace("{name}", ApiClient.urlEncode(name)); - webClientRequestBuilder.path(path); - webClientRequestBuilder.accept(MediaType.APPLICATION_JSON); - - return webClientRequestBuilder; - } - - /** - * Initiates the request for the getMessage operation. - * Optional customization point for subclasses. - * - * @param webClientRequestBuilder the request builder to use for submitting the request - * @param name the name to greet (required) - * @return {@code ApiResponse} for the submitted request - */ - protected ApiResponse getMessageSubmit(WebClientRequestBuilder webClientRequestBuilder, String name) { - Single webClientResponse = webClientRequestBuilder.submit(); - return ApiResponse.create(RESPONSE_TYPE_getMessage, webClientResponse); - } - - @Override - public ApiResponse updateGreeting(Message message) { - Objects.requireNonNull(message, "Required parameter 'message' not specified"); - WebClientRequestBuilder webClientRequestBuilder = updateGreetingRequestBuilder(message); - return updateGreetingSubmit(webClientRequestBuilder, message); - } - - /** - * Creates a {@code WebClientRequestBuilder} for the updateGreeting operation. - * Optional customization point for subclasses. - * - * @param message Message for the user (required) - * @return WebClientRequestBuilder for updateGreeting - */ - protected WebClientRequestBuilder updateGreetingRequestBuilder(Message message) { - WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient() - .method("PUT"); - - webClientRequestBuilder.path("/greet/greeting"); - webClientRequestBuilder.contentType(MediaType.APPLICATION_JSON); - webClientRequestBuilder.accept(MediaType.APPLICATION_JSON); - - return webClientRequestBuilder; - } - - /** - * Initiates the request for the updateGreeting operation. - * Optional customization point for subclasses. - * - * @param webClientRequestBuilder the request builder to use for submitting the request - * @param message Message for the user (required) - * @return {@code ApiResponse} for the submitted request - */ - protected ApiResponse updateGreetingSubmit(WebClientRequestBuilder webClientRequestBuilder, Message message) { - Single webClientResponse = webClientRequestBuilder.submit(message); - return ApiResponse.create(RESPONSE_TYPE_updateGreeting, webClientResponse); - } -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageService.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageService.java deleted file mode 100644 index b052a17004f..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/MessageService.java +++ /dev/null @@ -1,88 +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 org.openapitools.client.api; - -import io.helidon.common.http.Http; -import io.helidon.webserver.Handler; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; -import org.openapitools.client.ApiClient; -import org.openapitools.client.model.Message; - -public class MessageService implements Service { - - private final MessageApi api; - - public MessageService() { - ApiClient apiClient = ApiClient.builder().build(); - api = MessageApiImpl.create(apiClient); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules.get("/greet", this::getDefaultMessage); - rules.get("/greet/{name}", this::getMessage); - rules.put("/greet/greeting", Handler.create(Message.class, this::updateGreeting)); - } - - /** - * GET /greet : Return a worldly greeting message.. - * - * @param request the server request - * @param response the server response - */ - public void getDefaultMessage(ServerRequest request, ServerResponse response) { - api.getDefaultMessage() - .webClientResponse() - .flatMapSingle(serverResponse -> serverResponse.content().as(Message.class)) - .thenAccept(response::send); - } - - /** - * GET /greet/{name} : Return a greeting message using the name that was provided.. - * - * @param request the server request - * @param response the server response - */ - public void getMessage(ServerRequest request, ServerResponse response) { - String name = request.path().param("name"); - api.getMessage(name) - .webClientResponse() - .flatMapSingle(serverResponse -> serverResponse.content().as(Message.class)) - .thenAccept(response::send); - } - - /** - * PUT /greet/greeting : Set the greeting to use in future messages.. - * - * @param request the server request - * @param response the server response - * @param message Message for the user - */ - public void updateGreeting(ServerRequest request, ServerResponse response, Message message) { - api.updateGreeting(message) - .webClientResponse() - .thenAccept(content -> response.status(Http.Status.NO_CONTENT_204).send()); - } -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/ResponseType.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/ResponseType.java deleted file mode 100644 index 261095f26b1..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/ResponseType.java +++ /dev/null @@ -1,47 +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 org.openapitools.client.api; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -import io.helidon.common.GenericType; - -class ResponseType { - - static GenericType create(Type rawType, Type... typeParams) { - return typeParams.length == 0 - ? GenericType.create(rawType) - : GenericType.create(new ParameterizedType() { - - @Override - public Type[] getActualTypeArguments() { - return typeParams; - } - - @Override - public Type getRawType() { - return rawType; - } - - @Override - public Type getOwnerType() { - return null; - } - }); - } -} \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/package-info.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/package-info.java deleted file mode 100644 index e4f030f76ed..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/api/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. - */ - -/** - * APIs. - */ -package org.openapitools.client.api; diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/Message.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/Message.java deleted file mode 100644 index 53fdf19f62c..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/Message.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openapitools.client.model; - -/** - * An message for the user - **/ - -public class Message { - - private String message; - - private String greeting; - - /** - * Get message - * - * @return message - **/ - public String getMessage() { - return message; - } - - /** - * Set message - **/ - public void setMessage(String message) { - this.message = message; - } - - public Message message(String message) { - this.message = message; - return this; - } - - /** - * Get greeting - * - * @return greeting - **/ - public String getGreeting() { - return greeting; - } - - /** - * Set greeting - **/ - public void setGreeting(String greeting) { - this.greeting = greeting; - } - - public Message greeting(String greeting) { - this.greeting = greeting; - return this; - } - - - /** - * Create a string representation of this pojo. - **/ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Message {\n"); - - sb.append(" message: ").append(toIndentedString(message)).append("\n"); - sb.append(" greeting: ").append(toIndentedString(greeting)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private static String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/package-info.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/package-info.java deleted file mode 100644 index 7ecbbf9bcf7..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/model/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. - */ - -/** - * Models. - */ -package org.openapitools.client.model; diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/package-info.java b/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/package-info.java deleted file mode 100644 index 8a54190c1ae..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/java/org/openapitools/client/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon SE client. - */ -package org.openapitools.client; diff --git a/examples/openapi-tools/quickstart-se/se-client/src/main/resources/application.yaml b/examples/openapi-tools/quickstart-se/se-client/src/main/resources/application.yaml deleted file mode 100644 index 79e416107d3..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/main/resources/application.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 8081 - host: localhost \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/api/MessageApiTest.java b/examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/api/MessageApiTest.java deleted file mode 100644 index 1cf7a01e99c..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/api/MessageApiTest.java +++ /dev/null @@ -1,109 +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 org.openapitools.client.api; - -import java.util.List; -import java.util.Map; -import org.openapitools.client.model.Message; - -import org.openapitools.client.ApiClient; -import org.openapitools.client.ApiResponse; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.common.reactive.Single; -import io.helidon.webclient.WebClientResponse; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -/** - * - * OpenAPI Helidon Quickstart Test - * - * - * API tests for MessageApi - */ -public class MessageApiTest { - - private static ApiClient apiClient; - private static MessageApi api; - private static final String baseUrl = "http://localhost:8080"; - - @BeforeAll - public static void setup() { - apiClient = ApiClient.builder().build(); - api = MessageApiImpl.create(apiClient); - } - - /** - * Return a worldly greeting message. - */ - @Test - public void getDefaultMessageTest() { - - // TODO - uncomment the following two lines to invoke the service with valid parameters. - //ApiResponse response = api.getDefaultMessage(); - //response.webClientResponse().await(); - // TODO - check for appropriate return status - // assertThat("Return status", response.get().status().code(), is(expectedStatus)); - - // TODO: test validations - } - - /** - * Return a greeting message using the name that was provided. - */ - @Test - public void getMessageTest() { - // TODO - assign values to the input arguments. - String name = null; - - // TODO - uncomment the following two lines to invoke the service with valid parameters. - //ApiResponse response = api.getMessage(name); - //response.webClientResponse().await(); - // TODO - check for appropriate return status - // assertThat("Return status", response.get().status().code(), is(expectedStatus)); - - // TODO: test validations - } - - /** - * Set the greeting to use in future messages. - */ - @Test - public void updateGreetingTest() { - // TODO - assign values to the input arguments. - Message message = null; - - // TODO - uncomment the following two lines to invoke the service with valid parameters. - //ApiResponse response = api.updateGreeting(message); - //response.webClientResponse().await(); - // TODO - check for appropriate return status - // assertThat("Return status", response.get().status().code(), is(expectedStatus)); - - // TODO: test validations - } - -} diff --git a/examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/model/MessageTest.java b/examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/model/MessageTest.java deleted file mode 100644 index 8286df28f90..00000000000 --- a/examples/openapi-tools/quickstart-se/se-client/src/test/java/org/openapitools/client/model/MessageTest.java +++ /dev/null @@ -1,58 +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 org.openapitools.client.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.annotation.JsonValue; - -import org.junit.jupiter.api.Test; - - -/** - * Model tests for Message - */ -public class MessageTest { - private final Message model = new Message(); - - /** - * Model tests for Message - */ - @Test - public void testMessage() { - // TODO: test Message - } - - /** - * Test the property 'message' - */ - @Test - public void messageTest() { - // TODO: test message - } - - /** - * Test the property 'greeting' - */ - @Test - public void greetingTest() { - // TODO: test greeting - } - -} diff --git a/examples/openapi-tools/quickstart-se/se-server/README.md b/examples/openapi-tools/quickstart-se/se-server/README.md deleted file mode 100644 index d690bd60427..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Helidon SE Server with OpenAPI - -## Build and run - -With JDK11+ -```bash -mvn package -java -jar target/openapi-java-server.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/greet -curl -X GET http://localhost:8080/greet/{name} -curl -X PUT http://localhost:8080/greet/greeting - -``` - -## Try health and metrics - -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... -. . . - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge -. . . - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -{"base":... -. . . -``` \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-server/pom.xml b/examples/openapi-tools/quickstart-se/se-server/pom.xml deleted file mode 100644 index 303c17ad7f1..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/pom.xml +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../../applications/se/pom.xml - - org.openapitools - openapi-se-server - 1.0.0 - openapi-java-server - This is a sample for Helidon Quickstart project. - - - org.openapitools.server.Main - 0.2.3 - 6.2.1 - - - - - jakarta.validation - jakarta.validation-api - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.media - helidon-media-multipart - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics - - - io.helidon.openapi - helidon-openapi - - - org.openapitools - jackson-databind-nullable - ${version.jackson.databind.nullable} - - - io.helidon.media - helidon-media-jackson - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.helidon.build-tools - helidon-maven-plugin - - - third-party-license-report - - - - - - - - - openapi - - - - org.openapitools - openapi-generator-maven-plugin - ${version.openapi.generator.maven.plugin} - - - - generate - - - ${project.basedir}/src/main/resources/META-INF/openapi.yml - java-helidon-server - se - ${project.basedir} - - false - - - - - - - - - - diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/Main.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/Main.java deleted file mode 100644 index 46bbbfa3054..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/Main.java +++ /dev/null @@ -1,109 +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 org.openapitools.server; - -import org.openapitools.server.api.MessageServiceImpl; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.media.jackson.JacksonSupport; -import org.openapitools.server.api.JsonProvider; -import io.helidon.metrics.MetricsSupport; -import io.helidon.openapi.OpenAPISupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .addMediaSupport(JacksonSupport.create(JsonProvider.objectMapper())) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:8080"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link Routing}. - * - * @param config configuration of this server - * @return routing configured with JSON support, a health check, and a service - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - return Routing.builder() - .register(OpenAPISupport.create(config.get(OpenAPISupport.Builder.CONFIG_KEY))) - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register("/", new MessageServiceImpl()) - .build(); - } -} diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java deleted file mode 100644 index 5b8a8cf42dd..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/RFC3339DateFormat.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openapitools.server; - -import com.fasterxml.jackson.databind.util.StdDateFormat; - -import java.text.DateFormat; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.TimeZone; - -public class RFC3339DateFormat extends DateFormat { - private static final long serialVersionUID = 1L; - private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); - - private final StdDateFormat fmt = new StdDateFormat() - .withTimeZone(TIMEZONE_Z) - .withColonInTimeZone(true); - - public RFC3339DateFormat() { - this.calendar = new GregorianCalendar(); - } - - @Override - public Date parse(String source, ParsePosition pos) { - return fmt.parse(source, pos); - } - - @Override - public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { - return fmt.format(date, toAppendTo, fieldPosition); - } - - @Override - public Object clone() { - return this; - } -} \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/JsonProvider.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/JsonProvider.java deleted file mode 100644 index ea2fb5b5898..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/JsonProvider.java +++ /dev/null @@ -1,36 +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 org.openapitools.server.api; - -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -public class JsonProvider { - - public static ObjectMapper objectMapper() { - ObjectMapper mapper = new ObjectMapper(); - mapper.registerModule(new JavaTimeModule()); - mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); - mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false); - return mapper; - } -} \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageService.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageService.java deleted file mode 100644 index 8e4e23318c9..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageService.java +++ /dev/null @@ -1,66 +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 org.openapitools.server.api; - -import io.helidon.webserver.Handler; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; -import org.openapitools.server.model.Message; - -public interface MessageService extends Service { - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - default void update(Routing.Rules rules) { - rules.get("/greet", this::getDefaultMessage); - rules.get("/greet/{name}", this::getMessage); - rules.put("/greet/greeting", Handler.create(Message.class, this::updateGreeting)); - } - - - /** - * GET /greet : Return a worldly greeting message.. - * - * @param request the server request - * @param response the server response - */ - void getDefaultMessage(ServerRequest request, ServerResponse response); - - /** - * GET /greet/{name} : Return a greeting message using the name that was provided.. - * - * @param request the server request - * @param response the server response - */ - void getMessage(ServerRequest request, ServerResponse response); - - /** - * PUT /greet/greeting : Set the greeting to use in future messages.. - * - * @param request the server request - * @param response the server response - * @param message Message for the user - */ - void updateGreeting(ServerRequest request, ServerResponse response, Message message); - -} diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java deleted file mode 100644 index 92ea04e2710..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/MessageServiceImpl.java +++ /dev/null @@ -1,69 +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 org.openapitools.server.api; - -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Logger; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import io.helidon.common.http.Http; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; - -import org.openapitools.server.model.Message; - -public class MessageServiceImpl implements MessageService { - - private final AtomicReference defaultMessage = new AtomicReference<>(); - - private static final int HTTP_CODE_NOT_IMPLEMENTED = 501; - private static final Logger LOGGER = Logger.getLogger(MessageService.class.getName()); - private static final ObjectMapper MAPPER = JsonProvider.objectMapper(); - - public MessageServiceImpl() { - Message message = new Message(); - message.setMessage("World"); - message.setGreeting("Hello"); - defaultMessage.set(message); - } - - public void getDefaultMessage(ServerRequest request, ServerResponse response) { - response.send(defaultMessage.get()); - } - - public void getMessage(ServerRequest request, ServerResponse response) { - String name = request.path().param("name"); - Message result = new Message(); - result.setMessage(name); - result.setGreeting(defaultMessage.get().getGreeting()); - response.send(result); - } - - public void updateGreeting(ServerRequest request, ServerResponse response, Message message) { - if (message.getGreeting() == null) { - Message jsonError = new Message(); - jsonError.setMessage("No greeting provided"); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonError); - return; - } - defaultMessage.set(message); - response.status(Http.Status.NO_CONTENT_204).send(); - } - -} diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/ValidatorUtils.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/ValidatorUtils.java deleted file mode 100644 index 656a125a0b5..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/ValidatorUtils.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 org.openapitools.server.api; - -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.util.Collection; -import java.util.Map; -import java.util.Objects; - -import jakarta.validation.ValidationException; - -/** - * Validation utility methods. - */ -public final class ValidatorUtils { - - public static boolean validateMin(Integer value, Integer min) { - checkNonNull(value); - if (value < min) { - throw new ValidationException(String.format("%s is less than %s", value, min)); - } - return true; - } - - public static boolean validateMax(Integer value, Integer max) { - checkNonNull(value); - if (value > max) { - throw new ValidationException(String.format("%s is more than %s", value, max)); - } - return true; - } - - public static boolean validateSize(Object value, Integer min, Integer max) { - checkNonNull(value); - Integer size = -1; - if (value instanceof Map) { - size = ((Map) value).size(); - } - if (value instanceof CharSequence) { - size = ((CharSequence) value).length(); - } - if (value instanceof Collection) { - size = ((Collection) value).size(); - } - if (value.getClass().isArray()) { - size = Array.getLength(value); - } - if (size == -1) { - throw new ValidationException("Value has incorrect type"); - } - if (min != null) { - validateMin(size, min); - } - if (max != null) { - validateMax(size, max); - } - return true; - } - - public static boolean validatePattern(String value, String pattern) { - checkNonNull(value, pattern); - if (value.matches(pattern)) { - return true; - } - throw new ValidationException(String.format("'%s' does not match the pattern '%s'", value, pattern)); - } - - public static boolean validateMin(BigDecimal value, String stringMinValue, boolean inclusive) { - checkNonNull(value); - BigDecimal minValue = new BigDecimal(stringMinValue); - int result = value.compareTo(minValue); - if (inclusive) { - if (result >= 0) { - return true; - } - } else { - if (result > 0) { - return true; - } - } - throw new ValidationException( - String.format("%s is not valid value. Min value '%s'. Inclusive - %s.", value, stringMinValue, inclusive) - ); - } - - public static boolean validateMax(BigDecimal value, String stringMaxValue, boolean inclusive) { - checkNonNull(value); - BigDecimal maxValue = new BigDecimal(stringMaxValue); - int result = value.compareTo(maxValue); - if (inclusive) { - if (result <= 0) { - return true; - } - } else { - if (result < 0) { - return true; - } - } - throw new ValidationException( - String.format("%s is not valid value. Max value '%s'. Inclusive - %s.", value, stringMaxValue, inclusive) - ); - } - - public static void checkNonNull(Object... args) { - try { - for (Object o : args) { - Objects.requireNonNull(o); - } - } catch (Exception e) { - throw new ValidationException(e); - } - } -} \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/package-info.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/package-info.java deleted file mode 100644 index bdf4d662bff..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/api/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. - */ - -/** - * APIs. - */ -package org.openapitools.server.api; diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/Message.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/Message.java deleted file mode 100644 index 1f8866acf04..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/Message.java +++ /dev/null @@ -1,100 +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 org.openapitools.server.model; - -/** - * An message for the user - */ -public class Message { - - private String message; - private String greeting; - - /** - * Default constructor. - */ - public Message() { - // JSON-B / Jackson - } - - /** - * Create Message. - * - * @param message message - * @param greeting greeting - */ - public Message( - String message, - String greeting - ) { - this.message = message; - this.greeting = greeting; - } - - - /** - * Get message - * - * @return message - */ - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - /** - * Get greeting - * - * @return greeting - */ - public String getGreeting() { - return greeting; - } - - public void setGreeting(String greeting) { - this.greeting = greeting; - } - - /** - * Create a string representation of this pojo. - **/ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Message {\n"); - - sb.append(" message: ").append(toIndentedString(message)).append("\n"); - sb.append(" greeting: ").append(toIndentedString(greeting)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private static String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} - diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/package-info.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/package-info.java deleted file mode 100644 index 416edf3da68..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/model/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. - */ - -/** - * Models. - */ -package org.openapitools.server.model; diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/package-info.java b/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/package-info.java deleted file mode 100644 index d7e08811cc5..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/java/org/openapitools/server/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon SE server. - */ -package org.openapitools.server; diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/resources/META-INF/openapi.yml b/examples/openapi-tools/quickstart-se/se-server/src/main/resources/META-INF/openapi.yml deleted file mode 100644 index c2b85c23770..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/resources/META-INF/openapi.yml +++ /dev/null @@ -1,104 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -openapi: 3.0.0 -info: - description: This is a sample for Helidon Quickstart project. - license: - name: Apache-2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - title: OpenAPI Helidon Quickstart - version: 1.0.0 -servers: -- url: http://localhost:8080 -tags: -- name: message -paths: - /greet: - get: - operationId: getDefaultMessage - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: successful operation - summary: Return a worldly greeting message. - tags: - - message - x-accepts: application/json - /greet/greeting: - put: - operationId: updateGreeting - requestBody: - $ref: '#/components/requestBodies/Message' - responses: - "200": - description: successful operation - "400": - description: No greeting provided - summary: Set the greeting to use in future messages. - tags: - - message - x-content-type: application/json - x-accepts: application/json - /greet/{name}: - get: - operationId: getMessage - parameters: - - description: the name to greet - explode: false - in: path - name: name - required: true - schema: - type: string - style: simple - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: successful operation - summary: Return a greeting message using the name that was provided. - tags: - - message - x-accepts: application/json -components: - requestBodies: - Message: - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: Message for the user - required: true - schemas: - Message: - description: An message for the user - example: - greeting: greeting - message: message - properties: - message: - format: int64 - type: string - greeting: - format: int64 - type: string - type: object diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/resources/application.yaml b/examples/openapi-tools/quickstart-se/se-server/src/main/resources/application.yaml deleted file mode 100644 index 14b180deec0..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/resources/application.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 8080 - host: localhost diff --git a/examples/openapi-tools/quickstart-se/se-server/src/main/resources/logging.properties b/examples/openapi-tools/quickstart-se/se-server/src/main/resources/logging.properties deleted file mode 100644 index d73eb5b6607..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/MainTest.java b/examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/MainTest.java deleted file mode 100644 index 891e993d270..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/MainTest.java +++ /dev/null @@ -1,63 +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 org.openapitools.server; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; - -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -@Disabled -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - - @BeforeAll - public static void startTheServer() throws Exception { - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - public static void stopServer() throws Exception { - if (webServer != null) { - webServer.shutdown() - .toCompletableFuture() - .get(10, TimeUnit.SECONDS); - } - } - - @Test - public void test() throws Exception { - } -} \ No newline at end of file diff --git a/examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/model/MessageTest.java b/examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/model/MessageTest.java deleted file mode 100644 index 262814daef0..00000000000 --- a/examples/openapi-tools/quickstart-se/se-server/src/test/java/org/openapitools/server/model/MessageTest.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 org.openapitools.server.model; - -import org.junit.jupiter.api.Test; - -/** - * Model tests for Message - */ -public class MessageTest { - private final Message model = new Message(); - - /** - * Model tests for Message - */ - @Test - public void testMessage() { - // TODO: test Message - } - - /** - * Test the property 'message' - */ - @Test - public void messageTest() { - // TODO: test message - } - - /** - * Test the property 'greeting' - */ - @Test - public void greetingTest() { - // TODO: test greeting - } - -} diff --git a/examples/openapi-tools/quickstart.yaml b/examples/openapi-tools/quickstart.yaml deleted file mode 100644 index 534d98bef8d..00000000000 --- a/examples/openapi-tools/quickstart.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -openapi: 3.0.0 -servers: - - url: 'http://localhost:8080' -info: - description: >- - This is a sample for Helidon Quickstart project. - version: 1.0.0 - title: OpenAPI Helidon Quickstart - license: - name: Apache-2.0 - url: 'https://www.apache.org/licenses/LICENSE-2.0.html' -tags: - - name: message -paths: - /greet: - get: - tags: - - message - summary: Return a worldly greeting message. - operationId: getDefaultMessage - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - /greet/greeting: - put: - tags: - - message - summary: Set the greeting to use in future messages. - operationId: updateGreeting - responses: - '200': - description: successful operation - '400': - description: No greeting provided - requestBody: - $ref: '#/components/requestBodies/Message' - '/greet/{name}': - get: - tags: - - message - summary: Return a greeting message using the name that was provided. - operationId: getMessage - parameters: - - name: name - in: path - description: the name to greet - required: true - schema: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Message' -components: - requestBodies: - Message: - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: Message for the user - required: true - schemas: - Message: - description: An message for the user - type: object - properties: - message: - type: string - format: int64 - greeting: - type: string - format: int64 diff --git a/examples/openapi/README.md b/examples/openapi/README.md deleted file mode 100644 index baf86178283..00000000000 --- a/examples/openapi/README.md +++ /dev/null @@ -1,36 +0,0 @@ - -# Helidon SE OpenAPI Example - -This example shows a simple greeting application, similar to the one from the -Helidon SE QuickStart, enhanced with OpenAPI support. - -Most of the OpenAPI document in this example comes from a static file packaged -with the application. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-openapi.jar -``` - -Try the endpoints: - -``` -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/openapi -[lengthy OpenAPI document] -``` - -The output describes not only then endpoints in `GreetService` as described in -the static file but also an endpoint contributed by the `SimpleAPIModelReader`. diff --git a/examples/openapi/pom.xml b/examples/openapi/pom.xml deleted file mode 100644 index cc93b1b3dd5..00000000000 --- a/examples/openapi/pom.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../applications/se/pom.xml - - io.helidon.examples - helidon-examples-openapi - Helidon Examples OpenAPI - - - Basic illustration of OpenAPI support in Helidon SE - - - - io.helidon.examples.openapi.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.openapi - helidon-openapi - - - io.helidon.metrics - helidon-metrics - runtime - - - io.helidon.webclient - helidon-webclient - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetService.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetService.java deleted file mode 100644 index 98dc63774c9..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetService.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.openapi; - -import java.util.Collections; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonReaderFactory; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private static final JsonReaderFactory JSON_RF = Json.createReaderFactory(Collections.emptyMap()); - - GreetService(Config config) { - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - } - - /** - * A service registers itself by updating the routine rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - GreetingMessage msg = new GreetingMessage(String.format("%s %s!", greeting, name)); - response.send(msg.forRest()); - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey(GreetingMessage.JSON_LABEL)) { - JsonObject jsonErrorObject = JSON_BF.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting = GreetingMessage.fromRest(jo).getMessage(); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class).thenAccept(jo -> updateGreetingFromJson(jo, response)); - } - -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetingMessage.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetingMessage.java deleted file mode 100644 index 205b766133b..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetingMessage.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.openapi; - -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * POJO for the greeting message exchanged between the server and the client. - */ -public class GreetingMessage { - - /** - * Label for tagging a {@code GreetingMessage} instance in JSON. - */ - public static final String JSON_LABEL = "greeting"; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private String message; - - /** - * Create a new greeting with the specified message content. - * - * @param message the message to store in the greeting - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Returns the message value. - * - * @return the message - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message value to be set - */ - public void setMessage(String message) { - this.message = message; - } - - /** - * Converts a JSON object (typically read from the request payload) - * into a {@code GreetingMessage}. - * - * @param jsonObject the {@link JsonObject} to convert. - * @return {@code GreetingMessage} set according to the provided object - */ - public static GreetingMessage fromRest(JsonObject jsonObject) { - return new GreetingMessage(jsonObject.getString(JSON_LABEL)); - } - - /** - * Prepares a {@link JsonObject} corresponding to this instance. - * - * @return {@code JsonObject} representing this {@code GreetingMessage} instance - */ - public JsonObject forRest() { - JsonObjectBuilder builder = JSON_BF.createObjectBuilder(); - return builder.add(JSON_LABEL, message) - .build(); - } -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/Main.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/Main.java deleted file mode 100644 index a26cd3082cb..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/Main.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.openapi; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.openapi.OpenAPISupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Simple Hello World rest application. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - // Get webserver config from the "server" section of application.yaml and register JSON support - Single server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build() - .start(); - - server.thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - return server; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - GreetService greetService = new GreetService(config); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - return Routing.builder() - .register(OpenAPISupport.create(config.get(OpenAPISupport.Builder.CONFIG_KEY))) - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register("/greet", greetService) - .build(); - } - -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIFilter.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIFilter.java deleted file mode 100644 index 43b21000f1b..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIFilter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.openapi.internal; - -import java.util.Map; - -import org.eclipse.microprofile.openapi.OASFilter; -import org.eclipse.microprofile.openapi.models.Operation; -import org.eclipse.microprofile.openapi.models.PathItem; - -/** - * Example OpenAPI filter which hides a single endpoint from the OpenAPI document. - */ -public class SimpleAPIFilter implements OASFilter { - - @Override - public PathItem filterPathItem(PathItem pathItem) { - for (Map.Entry methodOp - : pathItem.getOperations().entrySet()) { - if (SimpleAPIModelReader.DOOMED_OPERATION_ID - .equals(methodOp.getValue().getOperationId())) { - return null; - } - } - return OASFilter.super.filterPathItem(pathItem); - } -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIModelReader.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIModelReader.java deleted file mode 100644 index 856e5fb2948..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/SimpleAPIModelReader.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.openapi.internal; - -import org.eclipse.microprofile.openapi.OASFactory; -import org.eclipse.microprofile.openapi.OASModelReader; -import org.eclipse.microprofile.openapi.models.OpenAPI; -import org.eclipse.microprofile.openapi.models.PathItem; -import org.eclipse.microprofile.openapi.models.Paths; - -/** - * Defines two paths using the OpenAPI model reader mechanism, one that should - * be suppressed by the filter class and one that should appear in the published - * OpenAPI document. - */ -public class SimpleAPIModelReader implements OASModelReader { - - /** - * Path for the example endpoint added by this model reader that should be visible. - */ - public static final String MODEL_READER_PATH = "/test/newpath"; - - /** - * Path for an endpoint that the filter should hide. - */ - public static final String DOOMED_PATH = "/test/doomed"; - - /** - * ID for an endpoint that the filter should hide. - */ - public static final String DOOMED_OPERATION_ID = "doomedPath"; - - /** - * Summary text for the endpoint. - */ - public static final String SUMMARY = "A sample test endpoint from ModelReader"; - - @Override - public OpenAPI buildModel() { - /* - * Add two path items, one of which we expect to be removed by - * the filter and a very simple one that will appear in the - * published OpenAPI document. - */ - PathItem newPathItem = OASFactory.createPathItem() - .GET(OASFactory.createOperation() - .operationId("newPath") - .summary(SUMMARY)); - PathItem doomedPathItem = OASFactory.createPathItem() - .GET(OASFactory.createOperation() - .operationId(DOOMED_OPERATION_ID) - .summary("This should become invisible")); - OpenAPI openAPI = OASFactory.createOpenAPI(); - Paths paths = OASFactory.createPaths() - .addPathItem(MODEL_READER_PATH, newPathItem) - .addPathItem(DOOMED_PATH, doomedPathItem); - openAPI.paths(paths); - - return openAPI; - } -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/package-info.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/package-info.java deleted file mode 100644 index 19c4a5d1780..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/internal/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Internal classes supporting the Helidon OpenAPI example. - */ -package io.helidon.examples.openapi.internal; diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/package-info.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/package-info.java deleted file mode 100644 index 7f41df26093..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example application showing support for OpenAPI in Helidon SE - *

- * Start with {@link io.helidon.examples.openapi.Main} class. - * - * @see io.helidon.examples.openapi.Main - */ -package io.helidon.examples.openapi; diff --git a/examples/openapi/src/main/resources/META-INF/openapi.yml b/examples/openapi/src/main/resources/META-INF/openapi.yml deleted file mode 100644 index 8a7c77a20cf..00000000000 --- a/examples/openapi/src/main/resources/META-INF/openapi.yml +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---- -openapi: 3.0.0 -info: - title: Helidon SE Quickstart Example - description: A very simple application to reply with friendly greetings - version: 1.0.0 - -servers: - - url: http://localhost:8080 - description: Local test server - -paths: - /greet: - get: - summary: Returns a generic greeting - description: Greets the user generically - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - /greet/greeting: - put: - summary: Set the greeting prefix - description: Permits the client to set the prefix part of the greeting ("Hello") - requestBody: - description: Conveys the new greeting prefix to use in building greetings - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - examples: - greeting: - summary: Example greeting message to update - value: New greeting message - responses: - "200": - description: OK - content: - application/json: {} - /greet/{name}: - get: - summary: Returns a personalized greeting - parameters: - - name: name - in: path - required: true - schema: - type: string - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' -components: - schemas: - GreetingMessage: - properties: - message: - type: string diff --git a/examples/openapi/src/main/resources/application.yaml b/examples/openapi/src/main/resources/application.yaml deleted file mode 100644 index 70b778ea690..00000000000 --- a/examples/openapi/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - -openapi: - filter: io.helidon.examples.openapi.internal.SimpleAPIFilter - model: - reader: io.helidon.examples.openapi.internal.SimpleAPIModelReader -# The following would change the endpoint path for retrieving the OpenAPI document -# web-context: /myopenapi diff --git a/examples/openapi/src/main/resources/logging.properties b/examples/openapi/src/main/resources/logging.properties deleted file mode 100644 index 20473988762..00000000000 --- a/examples/openapi/src/main/resources/logging.properties +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO -io.helidon.openapi.OpenAPISupport.level=FINER diff --git a/examples/openapi/src/test/java/io/helidon/examples/openapi/MainTest.java b/examples/openapi/src/test/java/io/helidon/examples/openapi/MainTest.java deleted file mode 100644 index d4da62fcd8b..00000000000 --- a/examples/openapi/src/test/java/io/helidon/examples/openapi/MainTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.openapi; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.MediaType; -import io.helidon.examples.openapi.internal.SimpleAPIModelReader; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonPointer; -import jakarta.json.JsonString; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - - static { - TEST_JSON_OBJECT = JSON_BF.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - @BeforeAll - public static void startTheServer() { - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - public static void stopServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - @Test - public void testHelloWorld() { - webClient.get() - .path("/greet") - .request(JsonObject.class) - .thenAccept(jsonObject -> assertThat(jsonObject.getString("greeting"), is("Hello World!"))) - .await(); - - webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .thenAccept(jsonObject -> assertThat(jsonObject.getString("greeting"), is("Hello Joe!"))) - .await(); - - webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .thenAccept(response -> assertThat(response.status().code(), is(204))) - .thenCompose(nothing -> webClient.get() - .path("/greet/Joe") - .request(JsonObject.class)) - .thenAccept(jsonObject -> assertThat(jsonObject.getString("greeting"), is("Hola Joe!"))) - .await(); - - webClient.get() - .path("/health") - .request() - .thenAccept(response -> { - assertThat(response.status().code(), is(200)); - response.close(); - }) - .await(); - - webClient.get() - .path("/metrics") - .request() - .thenAccept(response -> { - assertThat(response.status().code(), is(200)); - response.close(); - }) - .await(); - } - - @Test - public void testOpenAPI() { - /* - * If you change the OpenAPI endpoint path in application.yaml, then - * change the following path also. - */ - JsonObject jsonObject = webClient.get() - .accept(MediaType.APPLICATION_JSON) - .path("/openapi") - .request(JsonObject.class) - .await(); - JsonObject paths = jsonObject.getJsonObject("paths"); - - JsonPointer jp = Json.createPointer("/" + escape("/greet/greeting") + "/put/summary"); - JsonString js = (JsonString) jp.getValue(paths); - assertThat("/greet/greeting.put.summary not as expected", js.getString(), is("Set the greeting prefix")); - - jp = Json.createPointer("/" + escape(SimpleAPIModelReader.MODEL_READER_PATH) - + "/get/summary"); - js = (JsonString) jp.getValue(paths); - assertThat("summary added by model reader does not match", js.getString(), - is(SimpleAPIModelReader.SUMMARY)); - - jp = Json.createPointer("/" + escape(SimpleAPIModelReader.DOOMED_PATH)); - assertThat("/test/doomed should not appear but does", jp.containsValue(paths), is(false)); - } - - private static String escape(String path) { - return path.replace("/", "~1"); - } - -} diff --git a/examples/pom.xml b/examples/pom.xml deleted file mode 100644 index c254f431ecc..00000000000 --- a/examples/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - 4.0.0 - - io.helidon - helidon-project - 3.2.7-SNAPSHOT - - io.helidon.examples - helidon-examples-project - Helidon Examples - pom - - - true - true - true - true - true - true - - - - config - graphql - grpc - health - quickstarts - microprofile - media - openapi - openapi-tools - security - todo-app - translator-app - webserver - integrations - employee-app - dbclient - webclient - cors - messaging - logging - metrics - jbatch - - - - - - - org.codehaus.mojo - exec-maven-plugin - - ${mainClass} - - - - - - - diff --git a/examples/quickstarts/README.md b/examples/quickstarts/README.md deleted file mode 100644 index 33b80c93b54..00000000000 --- a/examples/quickstarts/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Helidon Quickstart Examples - -These are the examples used by the Helidon Getting Started guide, and -the quickstart Maven archetypes. All examples implement the same -simple greeting service, one using Helidon MP and one using Helidon SE. - -The `archetypes` directory contains scripts for building the Maven -archetypes from these examples. diff --git a/examples/quickstarts/helidon-quickstart-mp/.dockerignore b/examples/quickstarts/helidon-quickstart-mp/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-mp/.gitignore b/examples/quickstarts/helidon-quickstart-mp/.gitignore deleted file mode 100644 index 594f3abf63c..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile b/examples/quickstarts/helidon-quickstart-mp/Dockerfile deleted file mode 100644 index e7a36c50829..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2018, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-quickstart-mp.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-quickstart-mp.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink deleted file mode 100644 index 73698f0d9b5..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink +++ /dev/null @@ -1,41 +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. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -# Don't generate CDS archive to work around JVM bug https://bugs.openjdk.org/browse/JDK-8274944 -RUN mvn package -Pjlink-image -DskipTests -Djlink.image.addClassDataSharingArchive=false -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/helidon-quickstart-mp-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native deleted file mode 100644 index d47331a86b3..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2020, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0 as build - -# Install native-image -RUN gu install native-image - -WORKDIR /usr/share - -# Install maven -RUN set -x && \ - curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ - tar -xvf apache-maven-*-bin.tar.gz && \ - rm apache-maven-*-bin.tar.gz && \ - mv apache-maven-* maven && \ - ln -s /usr/share/maven/bin/mvn /bin/ - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM scratch -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-quickstart-mp . - -ENTRYPOINT ["./helidon-quickstart-mp"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/README.md b/examples/quickstarts/helidon-quickstart-mp/README.md deleted file mode 100644 index 4a025bd51e0..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/README.md +++ /dev/null @@ -1,166 +0,0 @@ -# Helidon Quickstart MP Example - -This example implements a simple Hello World REST service using MicroProfile. - -## Build and run - -With JDK17+ -```bash -mvn package -java -jar target/helidon-quickstart-mp.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} -``` - -## Try health and metrics - -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... -. . . - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge -. . . - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -{"base":... -. . . - -``` - -## Build the Docker Image - -``` -docker build -t helidon-quickstart-mp . -``` - -## Start the application with Docker - -``` -docker run --rm -p 8080:8080 helidon-quickstart-mp:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -``` -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deploy application -kubectl get service helidon-quickstart-mp # Verify deployed service -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `22.3.0` or later. - -``` -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-mp -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -``` -docker build -t helidon-quickstart-mp-native -f Dockerfile.native . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-quickstart-mp-native:latest -``` - - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -``` -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-mp-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -``` -docker build -t helidon-quickstart-mp-jri -f Dockerfile.jlink . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-quickstart-mp-jri:latest -``` - -See the start script help: - -``` -docker run --rm helidon-quickstart-mp-jri:latest --help -``` diff --git a/examples/quickstarts/helidon-quickstart-mp/app.yaml b/examples/quickstarts/helidon-quickstart-mp/app.yaml deleted file mode 100644 index 16dd9668e41..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp -spec: - type: NodePort - selector: - app: helidon-quickstart-mp - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-mp - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-mp - version: v1 - spec: - containers: - - name: helidon-quickstart-mp - image: helidon-quickstart-mp - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/build.gradle b/examples/quickstarts/helidon-quickstart-mp/build.gradle deleted file mode 100644 index 1dd86ab112e..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/build.gradle +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2018, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -plugins { - id 'java' - id 'org.kordamp.gradle.jandex' version '0.6.0' - id 'application' -} - -group = 'io.helidon.examples' -version = '1.0-SNAPSHOT' - -description = """helidon-quickstart-mp""" - -sourceCompatibility = 17 -targetCompatibility = 17 -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} - -ext { - helidonversion = '3.2.7-SNAPSHOT' - mainClass='io.helidon.microprofile.cdi.Main' -} - -repositories { - mavenCentral() - mavenLocal() - gradlePluginPortal() -} - -dependencies { - // import Helidon BOM - implementation enforcedPlatform("io.helidon:helidon-dependencies:${project.helidonversion}") - implementation 'io.helidon.microprofile.bundles:helidon-microprofile' - implementation 'org.glassfish.jersey.media:jersey-media-json-binding' - - runtimeOnly 'org.jboss:jandex' - runtimeOnly 'jakarta.activation:jakarta.activation-api' - - testImplementation 'io.helidon.microprofile.tests:helidon-microprofile-tests-junit5' - testImplementation 'org.junit.jupiter:junit-jupiter-api' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' -} - -test { - useJUnitPlatform() -} - -// define a custom task to copy all dependencies in the runtime classpath -// into build/libs/libs -// uses built-in Copy -task copyLibs(type: Copy) { - from configurations.runtimeClasspath - into 'build/libs/libs' -} - -// add it as a dependency of built-in task 'assemble' -copyLibs.dependsOn jar -assemble.dependsOn copyLibs - -// default jar configuration -// set the main classpath -// add each jar under build/libs/libs into the classpath -jar { - archiveFileName = "${project.name}.jar" - manifest { - attributes ('Main-Class': "${project.mainClass}" , - 'Class-Path': configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ') - ) - } -} - -application { - mainClass = "${project.mainClass}" -} - -// This is a work-around for running unit tests. -// Gradle places resource files under ${buildDir}/resources. In order for -// beans.xml to get picked up by CDI it must be co-located with the classes. -// So we move it before running tests. -// In either case it ends up AOK in the final jar artifact -task moveBeansXML { - doLast { - ant.move file: "${buildDir}/resources/main/META-INF/beans.xml", - todir: "${buildDir}/classes/java/main/META-INF" - } -} -compileTestJava.dependsOn jandex -jar.dependsOn jandex -test.dependsOn moveBeansXML -run.dependsOn moveBeansXML diff --git a/examples/quickstarts/helidon-quickstart-mp/pom.xml b/examples/quickstarts/helidon-quickstart-mp/pom.xml deleted file mode 100644 index bd987bae5f9..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples - helidon-quickstart-mp - Helidon Quickstart MP Example - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - org.jboss - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/quickstarts/helidon-quickstart-mp/settings.gradle b/examples/quickstarts/helidon-quickstart-mp/settings.gradle deleted file mode 100644 index e63c2aac63a..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/settings.gradle +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -rootProject.name = 'helidon-quickstart-mp' diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java deleted file mode 100644 index 50e8335a26c..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.mp; - -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.openapi.annotations.Operation; -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; - -/** - * A simple JAX-RS resource to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object. - */ -@Path("/greet") -public class GreetResource { - - /** - * The greeting message provider. - */ - private final GreetingProvider greetingProvider; - - /** - * Using constructor injection to get a configuration property. - * By default this gets the value from META-INF/microprofile-config - * - * @param greetingConfig the configured greeting message - */ - @Inject - public GreetResource(GreetingProvider greetingConfig) { - this.greetingProvider = greetingConfig; - } - - /** - * Return a worldly greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Operation(summary = "Returns a generic greeting", - description = "Greets the user generically") - @APIResponse(description = "Simple JSON containing the greeting", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class))) - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Operation(summary = "Returns a personalized greeting") - @APIResponse(description = "Simple JSON containing the greeting", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class))) - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RequestBody(name = "greeting", - required = true, - content = @Content(mediaType = "application/json", - schema = @Schema(type = SchemaType.OBJECT, requiredProperties = { "greeting" }))) - @APIResponses({ - @APIResponse(name = "normal", responseCode = "204", description = "Greeting updated"), - @APIResponse(name = "missing 'greeting'", responseCode = "400", - description = "JSON did not contain setting for 'greeting'")}) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java deleted file mode 100644 index eab1bac7963..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.quickstart.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java deleted file mode 100644 index 2eb86341bcb..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.quickstart.mp; - -import java.util.concurrent.atomic.AtomicReference; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Provider for greeting message. - */ -@ApplicationScoped -public class GreetingProvider { - private final AtomicReference message = new AtomicReference<>(); - - /** - * Create a new greeting provider, reading the message from configuration. - * - * @param message greeting to use - */ - @Inject - public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) { - this.message.set(message); - } - - String getMessage() { - return message.get(); - } - - void setMessage(String message) { - this.message.set(message); - } -} diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java deleted file mode 100644 index 87795470565..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quickstart MicroProfile example. - */ -@OpenAPIDefinition(info = @Info(title = "Helidon MP QuickStart Example", - version = "1.0.0", - description = "A very simple application to reply with friendly greetings") -) -package io.helidon.examples.quickstart.mp; - -import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition; -import org.eclipse.microprofile.openapi.annotations.info.Info; diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/beans.xml b/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 0828e0e8f12..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/logging.properties b/examples/quickstarts/helidon-quickstart-mp/src/main/resources/logging.properties deleted file mode 100644 index d4f05e084ad..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Quiet Weld -org.jboss.level=WARNING - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.microprofile.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java b/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java deleted file mode 100644 index 19d6292e621..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.mp; - -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -class MainTest { - private final WebTarget target; - - @Inject - MainTest(WebTarget target) { - this.target = target; - } - - @Test - void testHelloWorld() { - - GreetingMessage message = target.path("/greet") - .request() - .get(GreetingMessage.class); - assertThat("default message", message.getMessage(), - is("Hello World!")); - - message = target.path("/greet/Joe") - .request() - .get(GreetingMessage.class); - assertThat("hello Joe message", message.getMessage(), - is("Hello Joe!")); - - try (Response r = target.path("/greet/greeting") - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat("PUT status code", r.getStatus(), is(204)); - } - - message = target.path("/greet/Jose") - .request() - .get(GreetingMessage.class); - assertThat("hola Jose message", message.getMessage(), - is("Hola Jose!")); - - try (Response r = target.path("/metrics") - .request() - .get()) { - assertThat("GET metrics status code", r.getStatus(), is(200)); - } - - try (Response r = target.path("/health") - .request() - .get()) { - assertThat("GET health status code", r.getStatus(), is(200)); - } - } -} diff --git a/examples/quickstarts/helidon-quickstart-mp/src/test/resources/META-INF/microprofile-config.properties b/examples/quickstarts/helidon-quickstart-mp/src/test/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 4894cc74437..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/test/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -# Override configuration to use a random port for the unit tests -config_ordinal=1000 -# Microprofile server properties -server.port=-1 -server.host=0.0.0.0 diff --git a/examples/quickstarts/helidon-quickstart-se/.dockerignore b/examples/quickstarts/helidon-quickstart-se/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-se/.gitignore b/examples/quickstarts/helidon-quickstart-se/.gitignore deleted file mode 100644 index 241e8042d94..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile b/examples/quickstarts/helidon-quickstart-se/Dockerfile deleted file mode 100644 index 55ff21ad837..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (c) 2018, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-quickstart-se.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-quickstart-se.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink b/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink deleted file mode 100644 index d5ad3d113be..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink +++ /dev/null @@ -1,41 +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. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -# Don't generate CDS archive to work around JVM bug https://bugs.openjdk.org/browse/JDK-8274944 -RUN mvn package -Pjlink-image -DskipTests -Djlink.image.addClassDataSharingArchive=false -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/helidon-quickstart-se-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile.native b/examples/quickstarts/helidon-quickstart-se/Dockerfile.native deleted file mode 100644 index 546032110b4..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile.native +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0 as build - -# Install native-image -RUN gu install native-image - -WORKDIR /usr/share - -# Install maven -RUN set -x && \ - curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ - tar -xvf apache-maven-*-bin.tar.gz && \ - rm apache-maven-*-bin.tar.gz && \ - mv apache-maven-* maven && \ - ln -s /usr/share/maven/bin/mvn /bin/ - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM scratch -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-quickstart-se . - -ENTRYPOINT ["./helidon-quickstart-se"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/README.md b/examples/quickstarts/helidon-quickstart-se/README.md deleted file mode 100644 index c3da9e6d54c..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/README.md +++ /dev/null @@ -1,165 +0,0 @@ -# Helidon Quickstart SE Example - -This project implements a simple Hello World REST service using Helidon SE. - -## Build and run - -With JDK17+ -```bash -mvn package -java -jar target/helidon-quickstart-se.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} -``` - -## Try health and metrics - -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... -. . . - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge -. . . - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -{"base":... -. . . - -``` - -## Build the Docker Image - -``` -docker build -t helidon-quickstart-se . -``` - -## Start the application with Docker - -``` -docker run --rm -p 8080:8080 helidon-quickstart-se:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -``` -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deply application -kubectl get service helidon-quickstart-se # Get service info -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `22.3.0` or later. - -``` -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-se -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -``` -docker build -t helidon-quickstart-se-native -f Dockerfile.native . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-quickstart-se-native:latest -``` - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -``` -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-se-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -``` -docker build -t helidon-quickstart-se-jri -f Dockerfile.jlink . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-quickstart-se-jri:latest -``` - -See the start script help: - -``` -docker run --rm helidon-quickstart-se-jri:latest --help -``` diff --git a/examples/quickstarts/helidon-quickstart-se/app.yaml b/examples/quickstarts/helidon-quickstart-se/app.yaml deleted file mode 100644 index e5aa643c878..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se -spec: - type: NodePort - selector: - app: helidon-quickstart-se - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-se - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-se - version: v1 - spec: - containers: - - name: helidon-quickstart-se - image: helidon-quickstart-se - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/build.gradle b/examples/quickstarts/helidon-quickstart-se/build.gradle deleted file mode 100644 index c167d5497d9..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/build.gradle +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2018, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -plugins { - id 'java' - id 'application' -} - -group = 'io.helidon.examples' -version = '1.0-SNAPSHOT' - -description = """helidon-quickstart-se""" - -sourceCompatibility = 17 -targetCompatibility = 17 -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} - -ext { - helidonversion = '3.2.7-SNAPSHOT' - mainClass='io.helidon.examples.quickstart.se.Main' -} - -test { - useJUnitPlatform() -} - -repositories { - mavenCentral() - mavenLocal() -} - -dependencies { - // import Helidon BOM - implementation enforcedPlatform("io.helidon:helidon-dependencies:${project.helidonversion}") - implementation 'io.helidon.webserver:helidon-webserver' - implementation 'io.helidon.media:helidon-media-jsonp' - implementation 'io.helidon.config:helidon-config-yaml' - implementation 'io.helidon.health:helidon-health' - implementation 'io.helidon.health:helidon-health-checks' - implementation 'io.helidon.metrics:helidon-metrics' - - testImplementation 'org.junit.jupiter:junit-jupiter-api' - testImplementation 'io.helidon.webclient:helidon-webclient' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' -} - -// define a custom task to copy all dependencies in the runtime classpath -// into build/libs/libs -// uses built-in Copy -task copyLibs(type: Copy) { - from configurations.runtimeClasspath - into 'build/libs/libs' -} - -// add it as a dependency of built-in task 'assemble' -copyLibs.dependsOn jar -assemble.dependsOn copyLibs - -// default jar configuration -// set the main classpath -// add each jar under build/libs/libs into the classpath -jar { - archiveFileName = "${project.name}.jar" - manifest { - attributes ('Main-Class': "${project.mainClass}", - 'Class-Path': configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ') - ) - } -} - -application { - mainClass = "${project.mainClass}" -} - diff --git a/examples/quickstarts/helidon-quickstart-se/pom.xml b/examples/quickstarts/helidon-quickstart-se/pom.xml deleted file mode 100644 index fab310c75d1..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/pom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples - helidon-quickstart-se - 3.2.7-SNAPSHOT - Helidon Quickstart SE Example - - - io.helidon.examples.quickstart.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/quickstarts/helidon-quickstart-se/settings.gradle b/examples/quickstarts/helidon-quickstart-se/settings.gradle deleted file mode 100644 index e38154975c6..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/settings.gradle +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -rootProject.name = 'helidon-quickstart-se' diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java b/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java deleted file mode 100644 index 1a6a3d99280..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); - - GreetService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - } - - /** - * A service registers itself by updating the routing rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - if (ex.getCause() instanceof JsonException){ - - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } - -} diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java b/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java deleted file mode 100644 index 294be77b462..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.se; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - GreetService greetService = new GreetService(config); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - return Routing.builder() - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register("/greet", greetService) - .build(); - } -} diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java b/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java deleted file mode 100644 index fa1f34d7bd2..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quickstart demo application - *

- * Start with {@link io.helidon.examples.quickstart.se.Main} class. - * - * @see io.helidon.examples.quickstart.se.Main - */ -package io.helidon.examples.quickstart.se; diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/resources/application.yaml b/examples/quickstarts/helidon-quickstart-se/src/main/resources/application.yaml deleted file mode 100644 index 167d267715c..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 -# experimental: -# http2: -# enable: true -# max-content-length: 16384 \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/resources/logging.properties b/examples/quickstarts/helidon-quickstart-se/src/main/resources/logging.properties deleted file mode 100644 index fce837e53e0..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/quickstarts/helidon-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java b/examples/quickstarts/helidon-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java deleted file mode 100644 index aa31106e2e7..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.se; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - - static { - TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - @BeforeAll - static void startTheServer() { - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - static void stopServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - @Test - void testHelloWorld() { - JsonObject jsonObject; - WebClientResponse response; - - jsonObject = webClient.get() - .path("/greet") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello World!")); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello Joe!")); - - response = webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .await(); - assertThat(response.status().code(), is(204)); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hola Joe!")); - - response = webClient.get() - .path("/health") - .request() - .await(); - assertThat(response.status().code(), is(200)); - - response = webClient.get() - .path("/metrics") - .request() - .await(); - assertThat(response.status().code(), is(200)); - } - -} diff --git a/examples/quickstarts/helidon-quickstart-se/src/test/resources/config-profile.yaml b/examples/quickstarts/helidon-quickstart-se/src/test/resources/config-profile.yaml deleted file mode 100644 index 6290f00da98..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/test/resources/config-profile.yaml +++ /dev/null @@ -1,23 +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. -# - -sources: - - type: "inlined" - properties: - server.port: 0 - - type: "classpath" - properties: - resource: "application.yaml" diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/.dockerignore b/examples/quickstarts/helidon-standalone-quickstart-mp/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/.gitignore b/examples/quickstarts/helidon-standalone-quickstart-mp/.gitignore deleted file mode 100644 index 594f3abf63c..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile deleted file mode 100644 index b3ca729710f..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2018, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-standalone-quickstart-mp.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-standalone-quickstart-mp.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink deleted file mode 100644 index 73698f0d9b5..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink +++ /dev/null @@ -1,41 +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. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -# Don't generate CDS archive to work around JVM bug https://bugs.openjdk.org/browse/JDK-8274944 -RUN mvn package -Pjlink-image -DskipTests -Djlink.image.addClassDataSharingArchive=false -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/helidon-quickstart-mp-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native deleted file mode 100644 index de026dff89d..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2020, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0 as build - -# Install native-image -RUN gu install native-image - -WORKDIR /usr/share - -# Install maven -RUN set -x && \ - curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ - tar -xvf apache-maven-*-bin.tar.gz && \ - rm apache-maven-*-bin.tar.gz && \ - mv apache-maven-* maven && \ - ln -s /usr/share/maven/bin/mvn /bin/ - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM scratch -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-standalone-quickstart-mp . - -ENTRYPOINT ["./helidon-standalone-quickstart-mp"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/README.md b/examples/quickstarts/helidon-standalone-quickstart-mp/README.md deleted file mode 100644 index 544e5b9a6e4..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/README.md +++ /dev/null @@ -1,166 +0,0 @@ -# Helidon Standalone Quickstart MP Example - -This example implements a simple Hello World REST service using MicroProfile - with a standalone Maven pom. - -## Build and run - -With JDK17+ -```bash -mvn package -java -jar target/helidon-standalone-quickstart-mp.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} -``` - -## Try health and metrics - -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... -. . . - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge -. . . - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -{"base":... -. . . - -``` - -## Build the Docker Image - -``` -docker build -t helidon-standalone-quickstart-mp . -``` - -## Start the application with Docker - -``` -docker run --rm -p 8080:8080 helidon-standalone-quickstart-mp:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -``` -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deploy application -kubectl get service helidon-standalone-quickstart-mp # Verify deployed service -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `20.1.0` or later. - -``` -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-mp -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -``` -docker build -t helidon-quickstart-mp-native -f Dockerfile.native . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-quickstart-mp-native:latest -``` - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -``` -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-se-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -``` -docker build -t helidon-quickstart-mp-jri -f Dockerfile.jlink . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-quickstart-mp-jri:latest -``` - -See the start script help: - -``` -docker run --rm helidon-quickstart-mp-jri:latest --help -``` diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/app.yaml b/examples/quickstarts/helidon-standalone-quickstart-mp/app.yaml deleted file mode 100644 index 7d330579c02..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp -spec: - type: NodePort - selector: - app: helidon-quickstart-mp - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-mp - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-mp - version: v1 - spec: - containers: - - name: helidon-quickstart-mp - image: helidon-quickstart-mp - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml b/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml deleted file mode 100644 index 076cd0e667e..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml +++ /dev/null @@ -1,261 +0,0 @@ - - - - 4.0.0 - io.helidon.examples.quickstarts - helidon-standalone-quickstart-mp - 3.2.7-SNAPSHOT - Helidon Standalone Quickstart MP Example - - - 3.2.7-SNAPSHOT - io.helidon.microprofile.cdi.Main - - 17 - ${maven.compiler.source} - true - UTF-8 - UTF-8 - - - 3.11.0 - 3.6.0 - 2.7.5.1 - 1.6.0 - 3.1.2 - 3.0.5 - 3.0.4 - 1.2.3 - 3.0.2 - 1.5.0.Final - 0.6.1 - 3.3.1 - 3.1.2 - - - - - - io.helidon - helidon-dependencies - ${helidon.version} - pom - import - - - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - org.jboss - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - - - ${project.artifactId} - - - - org.apache.maven.plugins - maven-compiler-plugin - ${version.plugin.compiler} - - - org.apache.maven.plugins - maven-surefire-plugin - ${version.plugin.surefire} - - false - - ${project.build.outputDirectory}/logging.properties - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${version.plugin.failsafe} - - false - true - - - - org.apache.maven.plugins - maven-dependency-plugin - ${version.plugin.dependency} - - - org.apache.maven.plugins - maven-resources-plugin - ${version.plugin.resources} - - - org.apache.maven.plugins - maven-jar-plugin - ${version.plugin.jar} - - - - true - libs - ${mainClass} - false - - - - - - org.jboss.jandex - jandex-maven-plugin - ${version.plugin.jandex} - - - org.codehaus.mojo - exec-maven-plugin - ${version.plugin.exec} - - ${mainClass} - - - - io.helidon.build-tools - helidon-maven-plugin - ${version.plugin.helidon} - - - io.helidon.build-tools - helidon-cli-maven-plugin - ${version.plugin.helidon-cli} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - prepare-package - - copy-dependencies - - - ${project.build.directory}/libs - false - false - true - true - runtime - - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - jandex - - process-classes - - - - - - - - - native-image - - - - io.helidon.build-tools - helidon-maven-plugin - - - native-image - - native-image - - - - - - - - - io.helidon.integrations.graal - helidon-mp-graal-native-image-extension - - - - - jlink-image - - - - io.helidon.build-tools - helidon-maven-plugin - - - - jlink-image - - - - - - - - - diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java deleted file mode 100644 index 5de0bde8832..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.mp; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; - -/** - * A simple JAX-RS resource to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object. - */ -@Path("/greet") -@RequestScoped -public class GreetResource { - - /** - * The greeting message provider. - */ - private final GreetingProvider greetingProvider; - - /** - * Using constructor injection to get a configuration property. - * By default this gets the value from META-INF/microprofile-config - * - * @param greetingConfig the configured greeting message - */ - @Inject - public GreetResource(GreetingProvider greetingConfig) { - this.greetingProvider = greetingConfig; - } - - /** - * Return a worldly greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RequestBody(name = "greeting", - required = true, - content = @Content(mediaType = "application/json", - schema = @Schema(type = SchemaType.OBJECT, requiredProperties = { "greeting" }))) - @APIResponses({ - @APIResponse(name = "normal", responseCode = "204", description = "Greeting updated"), - @APIResponse(name = "missing 'greeting'", responseCode = "400", - description = "JSON did not contain setting for 'greeting'")}) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java deleted file mode 100644 index eab1bac7963..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.quickstart.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java deleted file mode 100644 index ab2c02af499..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.quickstart.mp; - -import java.util.concurrent.atomic.AtomicReference; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Provider for greeting message. - */ -@ApplicationScoped -public class GreetingProvider { - private final AtomicReference message = new AtomicReference<>(); - - /** - * Create a new greeting provider, reading the message from configuration. - * - * @param message greeting to use - */ - @Inject - public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) { - this.message.set(message); - } - - String getMessage() { - return message.get(); - } - - void setMessage(String message) { - this.message.set(message); - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java deleted file mode 100644 index fe70bc6d0d0..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quickstart MicroProfile example. - */ -@OpenAPIDefinition(info = @Info(title = "Helidon MP QuickStart Example", - version = "1.0.0", - description = "A very simple application to reply with friendly greetings") -) -package io.helidon.examples.quickstart.mp; - -import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition; -import org.eclipse.microprofile.openapi.annotations.info.Info; - diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/beans.xml b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index c2246f264ca..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/logging.properties b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/logging.properties deleted file mode 100644 index 496bbab6544..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -## Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler -# -## HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n -# -## Global logging level. Can be overridden by specific loggers -.level=INFO - -# Quiet Weld -org.jboss.level=WARNING - -# -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.microprofile.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java deleted file mode 100644 index 19d6292e621..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.mp; - -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -class MainTest { - private final WebTarget target; - - @Inject - MainTest(WebTarget target) { - this.target = target; - } - - @Test - void testHelloWorld() { - - GreetingMessage message = target.path("/greet") - .request() - .get(GreetingMessage.class); - assertThat("default message", message.getMessage(), - is("Hello World!")); - - message = target.path("/greet/Joe") - .request() - .get(GreetingMessage.class); - assertThat("hello Joe message", message.getMessage(), - is("Hello Joe!")); - - try (Response r = target.path("/greet/greeting") - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat("PUT status code", r.getStatus(), is(204)); - } - - message = target.path("/greet/Jose") - .request() - .get(GreetingMessage.class); - assertThat("hola Jose message", message.getMessage(), - is("Hola Jose!")); - - try (Response r = target.path("/metrics") - .request() - .get()) { - assertThat("GET metrics status code", r.getStatus(), is(200)); - } - - try (Response r = target.path("/health") - .request() - .get()) { - assertThat("GET health status code", r.getStatus(), is(200)); - } - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/.dockerignore b/examples/quickstarts/helidon-standalone-quickstart-se/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/.gitignore b/examples/quickstarts/helidon-standalone-quickstart-se/.gitignore deleted file mode 100644 index 241e8042d94..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile deleted file mode 100644 index feeebc4c675..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (c) 2018, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-standalone-quickstart-se.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-standalone-quickstart-se.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink deleted file mode 100644 index d5ad3d113be..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink +++ /dev/null @@ -1,41 +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. -# - -# 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -# Don't generate CDS archive to work around JVM bug https://bugs.openjdk.org/browse/JDK-8274944 -RUN mvn package -Pjlink-image -DskipTests -Djlink.image.addClassDataSharingArchive=false -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/helidon-quickstart-se-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native deleted file mode 100644 index a9f11fc89b1..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0 as build - -# Install native-image -RUN gu install native-image - -WORKDIR /usr/share - -# Install maven -RUN set -x && \ - curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ - tar -xvf apache-maven-*-bin.tar.gz && \ - rm apache-maven-*-bin.tar.gz && \ - mv apache-maven-* maven && \ - ln -s /usr/share/maven/bin/mvn /bin/ - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM scratch -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-standalone-quickstart-se . - -ENTRYPOINT ["./helidon-standalone-quickstart-se"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/README.md b/examples/quickstarts/helidon-standalone-quickstart-se/README.md deleted file mode 100644 index 08887994d89..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/README.md +++ /dev/null @@ -1,166 +0,0 @@ -# Helidon Standalone Quickstart SE Example - -This project implements a simple Hello World REST service using Helidon SE with - a standalone Maven pom. - -## Build and run - -With JDK17+ -```bash -mvn package -java -jar target/helidon-standalone-quickstart-se.jar -``` - -## Exercise the application - -``` -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} -``` - -## Try health and metrics - -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... -. . . - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge -. . . - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -{"base":... -. . . - -``` - -## Build the Docker Image - -``` -docker build -t helidon-standalone-quickstart-se . -``` - -## Start the application with Docker - -``` -docker run --rm -p 8080:8080 helidon-standalone-quickstart-se:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -``` -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deply application -kubectl get service helidon-standalone-quickstart-se # Get service info -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `22.3.0` or later. - -``` -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin - for more information. - -Start the application: - -``` -./target/helidon-standalone-quickstart-se -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -``` -docker build -t helidon-standalone-quickstart-se-native -f Dockerfile.native . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-standalone-quickstart-se-native:latest -``` - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -``` -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -``` -./target/helidon-quickstart-se-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -``` -docker build -t helidon-quickstart-se-jri -f Dockerfile.jlink . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 helidon-quickstart-se-jri:latest -``` - -See the start script help: - -``` -docker run --rm helidon-quickstart-se-jri:latest --help -``` diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/app.yaml b/examples/quickstarts/helidon-standalone-quickstart-se/app.yaml deleted file mode 100644 index 00fdab888f6..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se -spec: - type: NodePort - selector: - app: helidon-quickstart-se - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-se - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-se - version: v1 - spec: - containers: - - name: helidon-quickstart-se - image: helidon-quickstart-se - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml b/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml deleted file mode 100644 index 261a828c74b..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml +++ /dev/null @@ -1,250 +0,0 @@ - - - - 4.0.0 - io.helidon.examples.quickstarts - helidon-standalone-quickstart-se - 3.2.7-SNAPSHOT - Helidon Standalone Quickstart SE Example - - - 3.2.7-SNAPSHOT - io.helidon.examples.quickstart.se.Main - - 17 - ${maven.compiler.source} - true - UTF-8 - UTF-8 - - - 3.11.0 - 3.6.0 - 1.6.0 - 3.1.2 - 3.0.5 - 3.0.4 - 3.0.2 - 1.5.0.Final - 0.6.1 - 3.3.1 - 3.1.2 - - - - - - io.helidon - helidon-dependencies - ${helidon.version} - pom - import - - - - - - - io.helidon.bundles - helidon-bundles-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - - - ${project.artifactId} - - - - org.apache.maven.plugins - maven-compiler-plugin - ${version.plugin.compiler} - - - org.apache.maven.plugins - maven-surefire-plugin - ${version.plugin.surefire} - - false - - ${project.build.outputDirectory}/logging.properties - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${version.plugin.failsafe} - - false - true - - - - org.apache.maven.plugins - maven-dependency-plugin - ${version.plugin.dependency} - - - org.apache.maven.plugins - maven-resources-plugin - ${version.plugin.resources} - - - org.apache.maven.plugins - maven-jar-plugin - ${version.plugin.jar} - - - - true - libs - ${mainClass} - false - - - - - - org.codehaus.mojo - exec-maven-plugin - ${version.plugin.exec} - - ${mainClass} - - - - io.helidon.build-tools - helidon-maven-plugin - ${version.plugin.helidon} - - - io.helidon.build-tools - helidon-cli-maven-plugin - ${version.plugin.helidon-cli} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - prepare-package - - copy-dependencies - - - ${project.build.directory}/libs - false - false - true - true - runtime - - - - - - - - - - native-image - - - - io.helidon.build-tools - helidon-maven-plugin - - - - native-image - - - - - - - - - io.helidon.integrations.graal - helidon-graal-native-image-extension - - - - - jlink-image - - - - io.helidon.build-tools - helidon-maven-plugin - - - - jlink-image - - - - - - - - - diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java deleted file mode 100644 index 1a6a3d99280..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); - - GreetService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - } - - /** - * A service registers itself by updating the routing rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - if (ex.getCause() instanceof JsonException){ - - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } - -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java deleted file mode 100644 index 294be77b462..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.se; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - startServer(); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - return webserver; - } - - /** - * Creates new {@link Routing}. - * - * @return routing configured with JSON support, a health check, and a service - * @param config configuration of this server - */ - private static Routing createRouting(Config config) { - - MetricsSupport metrics = MetricsSupport.create(); - GreetService greetService = new GreetService(config); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - return Routing.builder() - .register(health) // Health at "/health" - .register(metrics) // Metrics at "/metrics" - .register("/greet", greetService) - .build(); - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java deleted file mode 100644 index 3edfa0c04b2..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Quickstart demo application - *

- * Start with {@link io.helidon.examples.quickstart.se.Main} class. - * - * @see io.helidon.examples.quickstart.se.Main - */ -package io.helidon.examples.quickstart.se; diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/helidon-example-reflection-config.json b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/helidon-example-reflection-config.json deleted file mode 100644 index fe51488c706..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/helidon-example-reflection-config.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/native-image.properties b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/native-image.properties deleted file mode 100644 index 2ef72b30947..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/native-image.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -Args=-H:ReflectionConfigurationResources=${.}/helidon-example-reflection-config.json diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/application.yaml b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/application.yaml deleted file mode 100644 index a0aec4e4038..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 -# experimental: -# http2: -# enable: true -# max-content-length: 16384 \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/logging.properties b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/logging.properties deleted file mode 100644 index fce837e53e0..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java deleted file mode 100644 index aa31106e2e7..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.quickstart.se; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - - static { - TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - @BeforeAll - static void startTheServer() { - webServer = Main.startServer().await(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - static void stopServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - @Test - void testHelloWorld() { - JsonObject jsonObject; - WebClientResponse response; - - jsonObject = webClient.get() - .path("/greet") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello World!")); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello Joe!")); - - response = webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .await(); - assertThat(response.status().code(), is(204)); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hola Joe!")); - - response = webClient.get() - .path("/health") - .request() - .await(); - assertThat(response.status().code(), is(200)); - - response = webClient.get() - .path("/metrics") - .request() - .await(); - assertThat(response.status().code(), is(200)); - } - -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/test/resources/config-profile.yaml b/examples/quickstarts/helidon-standalone-quickstart-se/src/test/resources/config-profile.yaml deleted file mode 100644 index 6290f00da98..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/test/resources/config-profile.yaml +++ /dev/null @@ -1,23 +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. -# - -sources: - - type: "inlined" - properties: - server.port: 0 - - type: "classpath" - properties: - resource: "application.yaml" diff --git a/examples/quickstarts/pom.xml b/examples/quickstarts/pom.xml deleted file mode 100644 index 3d715392b27..00000000000 --- a/examples/quickstarts/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.quickstarts - examples-quickstarts-project - Helidon Quickstart Examples - pom - - - helidon-quickstart-se - helidon-quickstart-mp - helidon-standalone-quickstart-mp - helidon-standalone-quickstart-se - - diff --git a/examples/security/README.md b/examples/security/README.md deleted file mode 100644 index e6b14226b7b..00000000000 --- a/examples/security/README.md +++ /dev/null @@ -1,4 +0,0 @@ - -# Helidon SE Security Examples - - diff --git a/examples/security/attribute-based-access-control/README.md b/examples/security/attribute-based-access-control/README.md deleted file mode 100644 index 3c3bbdfb813..00000000000 --- a/examples/security/attribute-based-access-control/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Helidon Security ABAC Example - -JAX-RS (Jersey) example for attribute based access control. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-abac.jar -``` diff --git a/examples/security/attribute-based-access-control/pom.xml b/examples/security/attribute-based-access-control/pom.xml deleted file mode 100644 index 6da7194e770..00000000000 --- a/examples/security/attribute-based-access-control/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.security - helidon-examples-security-abac - Helidon Security Examples ABAC - - - Example of attribute based access control. - - - - io.helidon.security.examples.abac.AbacJerseyMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.security.abac - helidon-security-abac-policy-el - - - org.glassfish - jakarta.el - - - org.jboss - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacApplication.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacApplication.java deleted file mode 100644 index 47ea7961ee9..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacApplication.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.abac; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * Application class of this MP application. - */ -@ApplicationScoped -@ApplicationPath("/rest") -public class AbacApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(AbacResource.class, AbacExplicitResource.class); - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacExplicitResource.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacExplicitResource.java deleted file mode 100644 index 5e9120745fa..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacExplicitResource.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.abac; - -import java.time.DayOfWeek; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.SecurityContext; -import io.helidon.security.SubjectType; -import io.helidon.security.abac.policy.PolicyValidator; -import io.helidon.security.abac.scope.ScopeValidator; -import io.helidon.security.abac.time.TimeValidator; -import io.helidon.security.annotations.Authenticated; -import io.helidon.security.annotations.Authorized; - -import jakarta.json.JsonString; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * Explicit authorization resource - authorization must be called by programmer. - */ -@Path("/explicit") -@TimeValidator.TimeOfDay(from = "08:15:00", to = "12:00:00") -@TimeValidator.TimeOfDay(from = "12:30:00", to = "17:30:00") -@TimeValidator.DaysOfWeek({DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY}) -@ScopeValidator.Scope("calendar_read") -@ScopeValidator.Scope("calendar_edit") -@PolicyValidator.PolicyStatement("${env.time.year >= 2017 && object.owner == subject.principal.id}") -@Authenticated -public class AbacExplicitResource { - /** - * A resource method to demonstrate explicit authorization. - * - * @param context security context (injected) - * @return "fine, sir" string; or a description of authorization failure - */ - @GET - @Authorized(explicit = true) - @AtnProvider.Authentication(value = "user", - roles = {"user_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - public Response process(@Context SecurityContext context) { - SomeResource res = new SomeResource("user"); - AuthorizationResponse atzResponse = context.authorize(res); - - if (atzResponse.isPermitted()) { - //do the update - return Response.ok().entity("fine, sir").build(); - } else { - return Response.status(Response.Status.FORBIDDEN) - .entity(atzResponse.description().orElse("Access not granted")) - .build(); - } - } - - /** - * A resource method to demonstrate explicit authorization - this should fail, as we do not call authorization. - * - * @param context security context (injected) - * @param object a JSON string - * @return "fine, sir" string; or a description of authorization failure - */ - @POST - @Path("/deny") - @Authorized(explicit = true) - @AtnProvider.Authentication(value = "user", - roles = {"user_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @Consumes(MediaType.APPLICATION_JSON) - public Response fail(@Context SecurityContext context, JsonString object) { - return Response.ok("This should not work").build(); - } - - /** - * Example resource. - */ - public static class SomeResource { - private String id; - private String owner; - private String message; - - private SomeResource(String owner) { - this.id = "id"; - this.owner = owner; - this.message = "Unit test"; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getOwner() { - return owner; - } - - public void setOwner(String owner) { - this.owner = owner; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacJerseyMain.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacJerseyMain.java deleted file mode 100644 index 9536c13bd0a..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacJerseyMain.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.abac; - -import io.helidon.config.Config; -import io.helidon.microprofile.server.Server; - -/** - * Jersey example for Attribute based access control. - */ -public final class AbacJerseyMain { - private static Server server; - - private AbacJerseyMain() { - } - - /** - * Main method of example. No arguments required, no configuration required. - * - * @param args empty is OK - * @throws Throwable if server fails to start - */ - public static void main(String[] args) throws Throwable { - server = startIt(); - } - - static Server startIt() { - Config config = Config.create(); - - Server server = Server.builder() - .config(config) - .port(8080) - .build() - .start(); - - System.out.printf("Started server on localhost:%d%n", server.port()); - System.out.println(); - System.out.println("***********************"); - System.out.println("** Endpoints: **"); - System.out.println("***********************"); - System.out.println("Using declarative authorization (ABAC):"); - System.out.printf(" http://localhost:%1$d/rest/attributes%n", server.port()); - System.out.println("Using explicit authorization (ABAC):"); - System.out.printf(" http://localhost:%1$d/rest/explicit%n", server.port()); - - return server; - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacResource.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacResource.java deleted file mode 100644 index 475509cc86f..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AbacResource.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.abac; - -import java.time.DayOfWeek; - -import io.helidon.security.SubjectType; -import io.helidon.security.abac.policy.PolicyValidator; -import io.helidon.security.abac.role.RoleValidator; -import io.helidon.security.abac.scope.ScopeValidator; -import io.helidon.security.abac.time.TimeValidator; -import io.helidon.security.annotations.Authenticated; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * Annotation only resource. - */ -@Path("/attributes") -@TimeValidator.TimeOfDay(from = "08:15:00", to = "12:00:00") -@TimeValidator.TimeOfDay(from = "12:30:00", to = "17:30:00") -@TimeValidator.DaysOfWeek({DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY}) -@ScopeValidator.Scope("calendar_read") -@ScopeValidator.Scope("calendar_edit") -@RoleValidator.Roles("user_role") -@RoleValidator.Roles(value = "service_role", subjectType = SubjectType.SERVICE) -@PolicyValidator.PolicyStatement("${env.time.year >= 2017}") -@Authenticated -public class AbacResource { - /** - * A resource method to demonstrate if access was successful or not. - * - * @return "hello" - */ - @GET - @AtnProvider.Authentication(value = "user", - roles = {"user_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - public String process() { - return "hello"; - } - - /** - * A resource method to demonstrate if access was successful or not. - * - * @return "hello" - */ - @GET - @Path("/deny") - @PolicyValidator.PolicyStatement("${env.time.year < 2017}") - @AtnProvider.Authentication(value = "user", scopes = {"calendar_read"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - public String deny() { - return "hello"; - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AtnProvider.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AtnProvider.java deleted file mode 100644 index 5e016e11612..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/AtnProvider.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.abac; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; - -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Grant; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Role; -import io.helidon.security.SecurityLevel; -import io.helidon.security.Subject; -import io.helidon.security.SubjectType; -import io.helidon.security.spi.AuthenticationProvider; -import io.helidon.security.spi.SynchronousProvider; - -/** - * Example authentication provider that reads annotation to create a subject. - */ -public class AtnProvider extends SynchronousProvider implements AuthenticationProvider { - @Override - protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { - List securityLevels = providerRequest.endpointConfig().securityLevels(); - ListIterator listIterator = securityLevels.listIterator(securityLevels.size()); - Subject user = null; - Subject service = null; - while (listIterator.hasPrevious()) { - SecurityLevel securityLevel = listIterator.previous(); - List authenticationAnnots = securityLevel - .filterAnnotations(Authentications.class, EndpointConfig.AnnotationScope.METHOD); - - List authentications = new LinkedList<>(); - authenticationAnnots.forEach(atn -> authentications.addAll(Arrays.asList(atn.value()))); - - - if (!authentications.isEmpty()) { - for (Authentication authentication : authentications) { - if (authentication.type() == SubjectType.USER) { - user = buildSubject(authentication); - } else { - service = buildSubject(authentication); - } - } - break; - } - } - return AuthenticationResponse.success(user, service); - } - - private Subject buildSubject(Authentication authentication) { - Subject.Builder subjectBuilder = Subject.builder(); - - subjectBuilder.principal(Principal.create(authentication.value())); - for (String role : authentication.roles()) { - subjectBuilder.addGrant(Role.create(role)); - } - for (String scope : authentication.scopes()) { - subjectBuilder.addGrant(Grant.builder() - .name(scope) - .type("scope") - .build()); - } - - return subjectBuilder.build(); - } - - @Override - public Collection> supportedAnnotations() { - return Set.of(Authentication.class); - } - - /** - * Authentication annotation. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @Documented - @Inherited - @Repeatable(Authentications.class) - public @interface Authentication { - /** - * Name of the principal. - * - * @return principal name - */ - String value(); - - /** - * Type of the subject, defaults to user. - * - * @return type - */ - SubjectType type() default SubjectType.USER; - - /** - * Granted roles. - * @return array of roles - */ - String[] roles() default ""; - - /** - * Granted scopes. - * @return array of scopes - */ - String[] scopes() default ""; - } - - /** - * Repeatable annotation for {@link Authentication}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @Documented - @Inherited - public @interface Authentications { - /** - * Repeating annotation. - * @return annotations - */ - Authentication[] value(); - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/package-info.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/package-info.java deleted file mode 100644 index 34c99f05d42..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/security/examples/abac/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of Attribute based access control (ABAC). - */ -package io.helidon.security.examples.abac; diff --git a/examples/security/attribute-based-access-control/src/main/resources/META-INF/beans.xml b/examples/security/attribute-based-access-control/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/security/attribute-based-access-control/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/security/attribute-based-access-control/src/main/resources/application.yaml b/examples/security/attribute-based-access-control/src/main/resources/application.yaml deleted file mode 100644 index a5e8c3ef263..00000000000 --- a/examples/security/attribute-based-access-control/src/main/resources/application.yaml +++ /dev/null @@ -1,88 +0,0 @@ -# -# Copyright (c) 2017, 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. -# - -# -# It is possible to provide default config values, here. -# - -server: - port: 8380 - -security: - providers: - - abac: - # prepares environment - # executes attribute validations - # validates that attributes were processed - # grants/denies access to resource - # - #### - # Combinations: - # # Will fail if any attribute is not validated and if any has failed validation - # fail-on-unvalidated: true - # fail-if-none-validated: true - # - # # Will fail if there is one or more attributes present and NONE of them is validated or if any has failed validation - # # Will NOT fail if there is at least one validated attribute and any number of not validated attributes (and NONE failed) - # fail-on-unvalidated: false - # fail-if-none-validated: true - # - # # Will fail if there is any attribute that failed validation - # # Will NOT fail if there are no failed validation or if there are NONE validated - # fail-on-unvalidated: false - # fail-if-none-validated: false - #### - # fail if an attribute was not validated (e.g. we do not know, whether it is valid or not) - # defaults to true - fail-on-unvalidated: true - # fail if none of the attributes were validated - # defaults to true - fail-if-none-validated: true -# policy-validator: -# validators: -# - class: "io.helidon.security.abac.policy.DefaultPolicyValidator" -# my-custom-policy-engine: -# some-key: "some value" -# another-key: "another value" - - atn: - class: "io.helidon.security.examples.abac.AtnProvider" - web-server: - paths: - - path: "/query" - audit: true - - path: "/noRoles" - methods: ["get"] - authenticate: true - - path: "/user[/{*}]" - methods: ["get"] - # implies authentication and authorization - abac: - scopes: ["calendar_read", "calendar_edit"] - time: - time-of-day: - - from: "08:15:00" - to: "12:00:00" - - from: "12:30" - to: "17:30" - days-of-week: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"] - policy: - #statement: "hasScopes('calendar_read','calendar_edit') AND timeOfDayBetween('8:15', '17:30')" - #ref: "service/policy_id" - statement: "object.owner == subject.principal.id" - resource: "com.oracle.ResourceProvider" - - - diff --git a/examples/security/attribute-based-access-control/src/main/resources/logging.properties b/examples/security/attribute-based-access-control/src/main/resources/logging.properties deleted file mode 100644 index 3f6b76d5ef0..00000000000 --- a/examples/security/attribute-based-access-control/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/basic-auth-with-static-content/README.md b/examples/security/basic-auth-with-static-content/README.md deleted file mode 100644 index 6245dd6c7ba..00000000000 --- a/examples/security/basic-auth-with-static-content/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Web Server Integration and Basic Authentication - -This example demonstrates integration of Web Server -based application with Security component and Basic authentication (from HttpAuthProvider), including -protection of a static resource. - -## Contents - -There are two examples with exactly the same behavior: -1. BasicExampleMain - shows how to programmatically secure application -2. BasicExampleConfigMain - shows how to secure application with configuration - 1. see src/main/resources/application.yaml for configuration - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-webserver-basic-auth.jar -``` - -Try the application: - -The application starts on a random port, the following assumes it is `56551` -```bash -curl http://localhost:56551/public -curl -u "jill:password" http://localhost:56551/noRoles -curl -u "john:password" http://localhost:56551/user -curl -u "jack:password" http://localhost:56551/admin -curl -v -u "john:password" http://localhost:56551/deny -curl -u "jack:password" http://localhost:56551/noAuthn -``` diff --git a/examples/security/basic-auth-with-static-content/pom.xml b/examples/security/basic-auth-with-static-content/pom.xml deleted file mode 100644 index 5f86e4aae74..00000000000 --- a/examples/security/basic-auth-with-static-content/pom.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-webserver-basic-uath - Helidon Security Examples HTTP Basic Authentication with Static Content - - - This example demonstrates Integration of RX Web Server based application with Security component, HTTP Basic - Authentication, and static content support - - - - io.helidon.security.examples.webserver.basic.BasicExampleConfigMain - - - - - io.helidon.security.integration - helidon-security-integration-webserver - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webclient - helidon-webclient - test - - - io.helidon.webclient - helidon-webclient-security - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderMain.java b/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderMain.java deleted file mode 100644 index af04e3a0041..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderMain.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.basic; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.LogConfig; -import io.helidon.common.http.MediaType; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.security.providers.httpauth.SecureUserStore; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -/** - * Example using {@link io.helidon.common.Builder} approach instead of configuration based approach. - */ -public final class BasicExampleBuilderMain { - // simple approach to user storage - for real world, use data store... - private static final Map USERS = new HashMap<>(); - - static { - USERS.put("jack", new MyUser("jack", "password".toCharArray(), Set.of("user", "admin"))); - USERS.put("jill", new MyUser("jill", "password".toCharArray(), Set.of("user"))); - USERS.put("john", new MyUser("john", "password".toCharArray(), Set.of())); - } - - private BasicExampleBuilderMain() { - } - - /** - * Entry point, starts the server. - * - * @param args not used - */ - public static void main(String[] args) { - BasicExampleUtil.startAndPrintEndpoints(BasicExampleBuilderMain::startServer); - } - - static WebServer startServer() { - LogConfig.initClass(); - - Routing routing = Routing.builder() - // must be configured first, to protect endpoints - .register(buildWebSecurity().securityDefaults(WebSecurity.authenticate())) - .any("/static[/{*}]", WebSecurity.rolesAllowed("user")) - .register("/static", StaticContentSupport.create("/WEB")) - .get("/noRoles", WebSecurity.enforce()) - .get("/user[/{*}]", WebSecurity.rolesAllowed("user")) - .get("/admin", WebSecurity.rolesAllowed("admin")) - // audit is not enabled for GET methods by default - .get("/deny", WebSecurity.rolesAllowed("deny").audit()) - // roles allowed imply authn and authz - .any("/noAuthn", WebSecurity.rolesAllowed("admin") - .authenticationOptional() - .audit()) - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - }) - .build(); - - return WebServer.builder() - .routing(routing) - // uncomment to use an explicit port - //.port(8080) - .build() - .start() - .await(10, TimeUnit.SECONDS); - - } - - private static WebSecurity buildWebSecurity() { - Security security = Security.builder() - .addAuthenticationProvider( - HttpBasicAuthProvider.builder() - .realm("helidon") - .userStore(buildUserStore()), - "http-basic-auth") - .build(); - return WebSecurity.create(security); - } - - private static SecureUserStore buildUserStore() { - return login -> Optional.ofNullable(USERS.get(login)); - } - - private static class MyUser implements SecureUserStore.User { - private final String login; - private final char[] password; - private final Set roles; - - private MyUser(String login, char[] password, Set roles) { - this.login = login; - this.password = password; - this.roles = roles; - } - - private char[] password() { - return password; - } - - @Override - public boolean isPasswordValid(char[] password) { - return Arrays.equals(password(), password); - } - - @Override - public Set roles() { - return roles; - } - - @Override - public String login() { - return login; - } - } -} diff --git a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigMain.java b/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigMain.java deleted file mode 100644 index bf3c3f2b1a8..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigMain.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.basic; - -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.LogConfig; -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.security.SecurityContext; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -/** - * Example using configuration based approach. - */ -public final class BasicExampleConfigMain { - private BasicExampleConfigMain() { - } - - /** - * Entry point, starts the server. - * @param args not used - */ - public static void main(String[] args) { - BasicExampleUtil.startAndPrintEndpoints(BasicExampleConfigMain::startServer); - } - - static WebServer startServer() { - LogConfig.initClass(); - - Config config = Config.create(); - - Routing routing = Routing.builder() - // must be configured first, to protect endpoints - .register(WebSecurity.create(config.get("security"))) - .register("/static", StaticContentSupport.create("/WEB")) - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - }) - .build(); - - return WebServer.builder() - .config(config.get("server")) - .routing(routing) - .build() - .start() - .await(10, TimeUnit.SECONDS); - - } -} diff --git a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleUtil.java b/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleUtil.java deleted file mode 100644 index 899ae9ede93..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/BasicExampleUtil.java +++ /dev/null @@ -1,63 +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.security.examples.webserver.basic; - -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -import io.helidon.webserver.WebServer; - -final class BasicExampleUtil { - private BasicExampleUtil() { - } - - static void startAndPrintEndpoints(Supplier startMethod) { - long t = System.nanoTime(); - - WebServer webServer = startMethod.get(); - - long time = System.nanoTime() - t; - System.out.printf("Server started in %d ms ms%n", TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - System.out.printf("Started server on localhost:%d%n", webServer.port()); - System.out.println(); - System.out.println("Users:"); - System.out.println("Jack/password in roles: user, admin"); - System.out.println("Jill/password in roles: user"); - System.out.println("John/password in no roles"); - System.out.println(); - System.out.println("***********************"); - System.out.println("** Endpoints: **"); - System.out.println("***********************"); - System.out.println("No authentication:"); - System.out.printf(" http://localhost:%1$d/public%n", webServer.port()); - System.out.println("No roles required, authenticated:"); - System.out.printf(" http://localhost:%1$d/noRoles%n", webServer.port()); - System.out.println("User role required:"); - System.out.printf(" http://localhost:%1$d/user%n", webServer.port()); - System.out.println("Admin role required:"); - System.out.printf(" http://localhost:%1$d/admin%n", webServer.port()); - System.out.println("Always forbidden (uses role nobody is in), audited:"); - System.out.printf(" http://localhost:%1$d/deny%n", webServer.port()); - System.out.println( - "Admin role required, authenticated, authentication optional, audited (always forbidden - challenge is not " - + "returned as authentication is optional):"); - System.out.printf(" http://localhost:%1$d/noAuthn%n", webServer.port()); - System.out.println("Static content, requires user role:"); - System.out.printf(" http://localhost:%1$d/static/index.html%n", webServer.port()); - System.out.println(); - } -} diff --git a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/package-info.java b/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/package-info.java deleted file mode 100644 index 95bf9df0bd5..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/security/examples/webserver/basic/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of basic authentication used with static content. - */ -package io.helidon.security.examples.webserver.basic; diff --git a/examples/security/basic-auth-with-static-content/src/main/resources/WEB/index.html b/examples/security/basic-auth-with-static-content/src/main/resources/WEB/index.html deleted file mode 100644 index 1d3ecc1d166..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/resources/WEB/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - -Hello, this is a static resource loaded from classpath. -

-The following endpoints are available on this server: -

- -The following users are configured: -
    -
  • jack/password in user and admin roles
  • -
  • jill/password in user roles
  • -
  • john/password that has no roles
  • -
- - - diff --git a/examples/security/basic-auth-with-static-content/src/main/resources/application.yaml b/examples/security/basic-auth-with-static-content/src/main/resources/application.yaml deleted file mode 100644 index 63a3e5330db..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/resources/application.yaml +++ /dev/null @@ -1,60 +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. -# - -# To configure an explicit port: -# server.port: 8080 - -security: - config: - # Configuration of secured config (encryption of passwords in property files) - # Set to true for production - if set to true, clear text passwords will cause failure - require-encryption: false - providers: - - http-basic-auth: - realm: "helidon" - users: - - login: "jack" - password: "${CLEAR=password}" - roles: [ "user", "admin" ] - - login: "jill" - password: "${CLEAR=password}" - roles: [ "user" ] - - login: "john" - password: "${CLEAR=password}" - roles: [ ] - web-server: - # Configuration of integration with web server - defaults: - authenticate: true - paths: - - path: "/noRoles" - methods: [ "get" ] - - path: "/user[/{*}]" - methods: [ "get" ] - roles-allowed: [ "user" ] - - path: "/admin" - methods: [ "get" ] - roles-allowed: [ "admin" ] - - path: "/deny" - methods: [ "get" ] - roles-allowed: [ "deny" ] - audit: true - - path: "/noAuthn" - roles-allowed: [ "admin" ] - authentication-optional: true - audit: true - - path: "/static[/{*}]" - roles-allowed: "user" diff --git a/examples/security/basic-auth-with-static-content/src/main/resources/logging.properties b/examples/security/basic-auth-with-static-content/src/main/resources/logging.properties deleted file mode 100644 index 7cd24e811fc..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/resources/logging.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n -#All log level details -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderTest.java b/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderTest.java deleted file mode 100644 index 909c22bb9d1..00000000000 --- a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleBuilderTest.java +++ /dev/null @@ -1,46 +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.security.examples.webserver.basic; - -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Unit test for {@link io.helidon.security.examples.webserver.basic.BasicExampleBuilderMain}. - */ -public class BasicExampleBuilderTest extends BasicExampleTest { - - private static WebServer server; - - @BeforeAll - public static void startServer() { - // start the test - server = BasicExampleBuilderMain.startServer(); - } - - @AfterAll - public static void stopServer() { - stopServer(server); - } - - @Override - String getServerBase() { - return "http://localhost:" + server.port(); - } -} diff --git a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigTest.java b/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigTest.java deleted file mode 100644 index dce551e0478..00000000000 --- a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleConfigTest.java +++ /dev/null @@ -1,46 +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.security.examples.webserver.basic; - -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Unit test for {@link io.helidon.security.examples.webserver.basic.BasicExampleConfigMain}. - */ -public class BasicExampleConfigTest extends BasicExampleTest { - - private static WebServer server; - - @BeforeAll - public static void startServer() { - // start the test - server = BasicExampleConfigMain.startServer(); - } - - @AfterAll - public static void stopServer() { - stopServer(server); - } - - @Override - String getServerBase() { - return "http://localhost:" + server.port(); - } -} diff --git a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleTest.java b/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleTest.java deleted file mode 100644 index 6409264a2f8..00000000000 --- a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/security/examples/webserver/basic/BasicExampleTest.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.basic; - -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Abstract class with tests for this example (used by programmatic and config based tests). - */ -public abstract class BasicExampleTest { - private static WebClient client; - - @BeforeAll - public static void classInit() { - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.builder() - .build()) - .build(); - - WebClientSecurity securityService = WebClientSecurity.create(security); - - client = WebClient.builder() - .addService(securityService) - .build(); - } - - static void stopServer(WebServer server) { - long t = System.nanoTime(); - server.shutdown().await(5, TimeUnit.SECONDS); - - long time = System.nanoTime() - t; - System.out.println("Server shutdown in " + TimeUnit.NANOSECONDS.toMillis(time) + " ms"); - } - - abstract String getServerBase(); - - //now for the tests - @Test - public void testPublic() { - //Must be accessible without authentication - WebClientResponse response = client.get() - .uri(getServerBase() + "/public") - .request() - .await(10, TimeUnit.SECONDS); - - assertThat(response.status(), is(Http.Status.OK_200)); - String entity = response.content().as(String.class).await(10, TimeUnit.SECONDS); - assertThat(entity, containsString("")); - } - - @Test - public void testNoRoles() { - String url = getServerBase() + "/noRoles"; - - testNotAuthorized(url); - - //Must be accessible with authentication - to everybody - testProtected(url, "jack", "password", Set.of("admin", "user"), Set.of()); - testProtected(url, "jill", "password", Set.of("user"), Set.of("admin")); - testProtected(url, "john", "password", Set.of(), Set.of("admin", "user")); - } - - @Test - public void testUserRole() { - String url = getServerBase() + "/user"; - - testNotAuthorized(url); - - //Jack and Jill allowed (user role) - testProtected(url, "jack", "password", Set.of("admin", "user"), Set.of()); - testProtected(url, "jill", "password", Set.of("user"), Set.of("admin")); - testProtectedDenied(url, "john", "password"); - } - - @Test - public void testAdminRole() { - String url = getServerBase() + "/admin"; - - testNotAuthorized(url); - - //Only jack is allowed - admin role... - testProtected(url, "jack", "password", Set.of("admin", "user"), Set.of()); - testProtectedDenied(url, "jill", "password"); - testProtectedDenied(url, "john", "password"); - } - - @Test - public void testDenyRole() { - String url = getServerBase() + "/deny"; - - testNotAuthorized(url); - - // nobody has the correct role - testProtectedDenied(url, "jack", "password"); - testProtectedDenied(url, "jill", "password"); - testProtectedDenied(url, "john", "password"); - } - - @Test - public void getNoAuthn() { - String url = getServerBase() + "/noAuthn"; - //Must NOT be accessible without authentication - WebClientResponse response = client.get().uri(url).request().await(5, TimeUnit.SECONDS); - - // authentication is optional, so we are not challenged, only forbidden, as the role can never be there... - assertThat(response.status(), is(Http.Status.FORBIDDEN_403)); - } - - private void testNotAuthorized(String uri) { - //Must NOT be accessible without authentication - WebClientResponse response = client.get().uri(uri).request().await(5, TimeUnit.SECONDS); - - assertThat(response.status(), is(Http.Status.UNAUTHORIZED_401)); - String header = response.headers().first("WWW-Authenticate").get(); - assertThat(header.toLowerCase(), containsString("basic")); - assertThat(header, containsString("helidon")); - } - - private WebClientResponse callProtected(String uri, String username, String password) { - // here we call the endpoint - return client.get() - .uri(uri) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, username) - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, password) - .request() - .await(5, TimeUnit.SECONDS); - } - - private void testProtectedDenied(String uri, - String username, - String password) { - - WebClientResponse response = callProtected(uri, username, password); - assertThat(response.status(), is(Http.Status.FORBIDDEN_403)); - } - - private void testProtected(String uri, - String username, - String password, - Set expectedRoles, - Set invalidRoles) { - - WebClientResponse response = callProtected(uri, username, password); - - String entity = response.content().as(String.class).await(5, TimeUnit.SECONDS); - - assertThat(response.status(), is(Http.Status.OK_200)); - - // check login - assertThat(entity, containsString("id='" + username + "'")); - // check roles - expectedRoles.forEach(role -> assertThat(entity, containsString(":" + role))); - invalidRoles.forEach(role -> assertThat(entity, not(containsString(":" + role)))); - } -} diff --git a/examples/security/google-login/README.md b/examples/security/google-login/README.md deleted file mode 100644 index ec25bc7efd3..00000000000 --- a/examples/security/google-login/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Integration with Google login button - -This example demonstrates Integration with Google login button on a web page. - -## Contents - -There are two examples with exactly the same behavior -1. builder - shows how to programmatically secure application -2. config - shows how to secure application with configuration - 1. see src/main/resources/application.conf - -There is a static web page in src/main/resources/WEB with a page to login to Google. - -This example requires a Google client id to run. -Update the following files with your client id (it should support http://localhost:8080): -1. src/main/resources/application.yaml - set security.properties.google-client-id or override it in a file in ~/helidon/examples.yaml -2. src/main/resources/WEB/index.html - update the meta tag in header with name "google-signin-client_id" -3. src/main/java/io/helidon/security/examples/google/GoogleBuilderMain.java - update the client id in builder of provider - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-google-login.jar -``` diff --git a/examples/security/google-login/pom.xml b/examples/security/google-login/pom.xml deleted file mode 100644 index 70f45b641f4..00000000000 --- a/examples/security/google-login/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-google-login - Helidon Security Examples Google Login - - - Example of Google login button integration with Security. - - - - io.helidon.security.examples.google.GoogleConfigMain - - - - - io.helidon.security.integration - helidon-security-integration-webserver - - - io.helidon.security.providers - helidon-security-providers-google-login - - - io.helidon.config - helidon-config-encryption - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.bundles - helidon-bundles-config - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - io.helidon.webclient - helidon-webclient - test - - - io.helidon.config - helidon-config-testing - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleBuilderMain.java b/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleBuilderMain.java deleted file mode 100644 index f06e30e2813..00000000000 --- a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleBuilderMain.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.google; - -import java.util.Optional; - -import io.helidon.common.http.MediaType; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.security.providers.google.login.GoogleTokenProvider; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -/** - * Google login button example main class using builders. - */ -public final class GoogleBuilderMain { - private static volatile WebServer theServer; - - private GoogleBuilderMain() { - } - - public static WebServer getTheServer() { - return theServer; - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - start(GoogleUtil.PORT); - } - - static int start(int port) { - Security security = Security.builder() - .addProvider(GoogleTokenProvider.builder() - .clientId("your-client-id.apps.googleusercontent.com")) - .build(); - WebSecurity ws = WebSecurity.create(security); - - Routing.Builder routing = Routing.builder() - .register(ws) - .get("/rest/profile", - WebSecurity.authenticate(), - (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Response from builder based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - req.next(); - }) - .register(StaticContentSupport.create("/WEB")); - - theServer = GoogleUtil.startIt(port, routing); - - return theServer.port(); - } -} diff --git a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleConfigMain.java b/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleConfigMain.java deleted file mode 100644 index 44241a83634..00000000000 --- a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleConfigMain.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.google; - -import java.util.Optional; - -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Google login button example main class using configuration. - */ -public final class GoogleConfigMain { - private static volatile WebServer theServer; - - private GoogleConfigMain() { - } - - public static WebServer getTheServer() { - return theServer; - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - start(GoogleUtil.PORT); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } - - static int start(int port) { - Config config = buildConfig(); - - Routing.Builder routing = Routing.builder() - // helper method to load both security and web server security from configuration - .register(WebSecurity.create(config.get("security"))) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/rest/profile", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Response from config based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - }) - .register(StaticContentSupport.create("/WEB")); - - theServer = GoogleUtil.startIt(port, routing); - - return theServer.port(); - } -} diff --git a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleUtil.java b/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleUtil.java deleted file mode 100644 index 2bf1eeb401d..00000000000 --- a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/GoogleUtil.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.google; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Google login example utilities. - */ -public final class GoogleUtil { - // do not change this constant, unless you modify configuration - // of Google application redirect URI - static final int PORT = 8080; - private static final int START_TIMEOUT_SECONDS = 10; - - private GoogleUtil() { - } - - static WebServer startIt(int port, Supplier routing) { - WebServer server = WebServer.builder(routing) - .port(port) - .build(); - - long t = System.nanoTime(); - - CountDownLatch cdl = new CountDownLatch(1); - - server.start().thenAccept(webServer -> { - long time = System.nanoTime() - t; - - System.out.printf("Server started in %d ms ms%n", TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - System.out.printf("Started server on localhost:%d%n", webServer.port()); - System.out.printf("You can access this example at http://localhost:%d/index.html%n", webServer.port()); - System.out.println(); - System.out.println(); - System.out.println("Check application.yaml in case you are behind a proxy to configure it"); - cdl.countDown(); - }); - - try { - cdl.await(START_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException("Failed to start server within defined timeout: " + START_TIMEOUT_SECONDS + " seconds"); - } - - return server; - } -} diff --git a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/package-info.java b/examples/security/google-login/src/main/java/io/helidon/security/examples/google/package-info.java deleted file mode 100644 index eeef4147c5b..00000000000 --- a/examples/security/google-login/src/main/java/io/helidon/security/examples/google/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of integration of Google Login button with security. - */ -package io.helidon.security.examples.google; diff --git a/examples/security/google-login/src/main/resources/WEB/index.html b/examples/security/google-login/src/main/resources/WEB/index.html deleted file mode 100644 index e4af8b0b29c..00000000000 --- a/examples/security/google-login/src/main/resources/WEB/index.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - Google Login Provider - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -

Login to Google.

-
-
-
- - -
-
-
- - - diff --git a/examples/security/google-login/src/main/resources/WEB/static/js/google-app.js b/examples/security/google-login/src/main/resources/WEB/static/js/google-app.js deleted file mode 100644 index cb6775b9c78..00000000000 --- a/examples/security/google-login/src/main/resources/WEB/static/js/google-app.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -(function () { - // new module with no dependencies - var app = angular.module('g', []); - - app.controller('GoogleController', ['$http', function ($http) { - this.callBackend = function () { - var accessToken = document.getElementById('gat_input').value; - - if (accessToken === "") { - console.log("No access token, not calling backend"); - alert("Please login before calling backend service"); - return; - } - console.log("Submit attempt to server: " + accessToken); - - $http({ - method: 'GET', - url: '/rest/profile', - headers: { - 'Authorization': "Bearer " + accessToken - } - }).success(function (data, status, headers, config) { - console.log('Successfully sent data to backend, received' + data); - alert(data); - }).error(function (data, status, headers, config) { - console.log('Failed to send data to backend. Status: ' + status); - alert(status + ", auth header: " + headers('WWW-Authenticate') + ", error: " + data); - }); - } - }]); -})(); diff --git a/examples/security/google-login/src/main/resources/application.yaml b/examples/security/google-login/src/main/resources/application.yaml deleted file mode 100644 index d0ff681e363..00000000000 --- a/examples/security/google-login/src/main/resources/application.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (c) 2016, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -security: - config.require-encryption: false - properties: - # This example loads overriding properties from ~/helidon/examples.yaml - # You may configure correct values in that file to leave this content intact - google-client-id: "your-app-id.apps.googleusercontent.com" - proxy-host: "" - providers: - - google-login: - # Create your own application in Google developer console - # Also update the client id configured in header of index.html - # Detailed how-to for login button (including links how to create an application): - # https://developers.google.com/identity/sign-in/web/sign-in - client-id: "${security.properties.google-client-id}" - # Defaults for Helidon - # realm: "helidon" - # Configure proxy host if needed - proxy-host: "${security.properties.proxy-host}" - # proxy-port: 80 - - # This is the default for GoogleTokenProvider - #token: - # header: "Authorization" - # or do not specify - then the whole header is considered to be the token value - # prefix: "bearer " - # optional alternative - looking for first matching group - # regexp: "bearer (.*)" - #} - web-server: - paths: - - path: "/rest/profile" - methods: ["get"] - authenticate: true - diff --git a/examples/security/google-login/src/main/resources/logging.properties b/examples/security/google-login/src/main/resources/logging.properties deleted file mode 100644 index 3f6b76d5ef0..00000000000 --- a/examples/security/google-login/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleBuilderMainTest.java b/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleBuilderMainTest.java deleted file mode 100644 index 7a4a3a711c2..00000000000 --- a/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleBuilderMainTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.google; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Unit test for {@link GoogleBuilderMain}. - */ -public class GoogleBuilderMainTest extends GoogleMainTest { - static int port; - - @BeforeAll - public static void initClass() throws InterruptedException { - port = GoogleBuilderMain.start(0); - } - - @AfterAll - public static void destroyClass() throws InterruptedException { - stopServer(GoogleBuilderMain.getTheServer()); - } - - @Override - int port() { - return port; - } -} diff --git a/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleConfigMainTest.java b/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleConfigMainTest.java deleted file mode 100644 index a3a5f6e6d66..00000000000 --- a/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleConfigMainTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.google; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Unit test for {@link GoogleConfigMain}. - */ -public class GoogleConfigMainTest extends GoogleMainTest { - static int port; - - @BeforeAll - public static void initClass() throws InterruptedException { - port = GoogleConfigMain.start(0); - } - - @AfterAll - public static void destroyClass() throws InterruptedException { - stopServer(GoogleConfigMain.getTheServer()); - } - - @Override - int port() { - return port; - } -} diff --git a/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleMainTest.java b/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleMainTest.java deleted file mode 100644 index f85fce05f66..00000000000 --- a/examples/security/google-login/src/test/java/io/helidon/security/examples/google/GoogleMainTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.google; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.config.testing.OptionalMatcher.value; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Google login common unit tests. - */ -public abstract class GoogleMainTest { - private static WebClient client; - - @BeforeAll - public static void classInit() { - client = WebClient.create(); - } - - static void stopServer(WebServer server) throws InterruptedException { - CountDownLatch cdl = new CountDownLatch(1); - long t = System.nanoTime(); - if (null == server) { - return; - } - server.shutdown().thenAccept(webServer -> { - long time = System.nanoTime() - t; - System.out.println("Server shutdown in " + TimeUnit.NANOSECONDS.toMillis(time) + " ms"); - cdl.countDown(); - }); - - if (!cdl.await(5, TimeUnit.SECONDS)) { - throw new IllegalStateException("Failed to shutdown server within 5 seconds"); - } - } - - @Test - public void testEndpoint() { - client.get() - .uri("http://localhost:" + port() + "/rest/profile") - .request() - .thenAccept(it -> { - assertThat(it.status(), is(Http.Status.UNAUTHORIZED_401)); - assertThat(it.headers().first(Http.Header.WWW_AUTHENTICATE), - value(is("Bearer realm=\"helidon\",scope=\"openid profile email\""))); - }) - .await(); - } - - abstract int port(); -} diff --git a/examples/security/idcs-login/README.md b/examples/security/idcs-login/README.md deleted file mode 100644 index 6f88cd17b70..00000000000 --- a/examples/security/idcs-login/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Security integration with IDCS - -This example demonstrates integration with IDCS (Oracle identity service, integrated with Open ID Connect provider). - -## Contents - -This project contains two samples, one (IdcsMain.java) which is configured via the application.yaml file and a second example (IdcsBuilderMain.java) which is configured in code. - -When configured the example exposes two HTTP endpoints `/jersey`, a rest endpoint protected by an IDCS application (with two scopes) and a second endpoint (/rest/profile) which is not protected. - -### IDCS Configuration - -Edit application.yaml for IdcsMain.java or OidcConfig variable definition for IdcsBuilderMain.java sample - -1. Log in to the IDCS console and create a new application of type "confidential app" -2. Within **Resources** - 1. Create two resources called `first_scope` and `second_scope` - 2. Primary Audience = `http://localhost:7987/"` (ensure there is a trailing /) -3. Within **Client Configuration** - 1. Register a client - 2. Allowed Grant Types = Client Credentials,JWT Assertion, Refresh Token, Authorization Code - 3. Check "Allow non-HTTPS URLs" - 4. Set Redirect URL to `http://localhost:7987/oidc/redirect` - 5. Client Type = Confidential - 6. Add all Scopes defined in the resources section - 7. Set allowed operations to `Introspect` - 8. Set Post Logout Redirect URL to `http://localhost:7987/loggedout` - -Ensure you save and *activate* the application - -### Code Configuration - -Edit application.yaml for IdcsMain.java or OidcConfig variable definition for IdcsBuilderMain.java sample - - 1. idcs-uri : Base URL of your idcs instance, usually something like https://idcs-.identity.oraclecloud.com - 2. idcs-client-id : This is obtained from your IDCS application in the IDCS console - 3. idcs-client-secret : This is obtained from your IDCS application in the IDCS console - 4. frontend-uri : This is the base URL of your application when run, e.g. `http://localhost:7987` - 5. proxy-host : Your proxy server if needed - 6. scope-audience : This is the scope audience which MUST match the primary audience in the IDCS resource, recommendation is not to have a trailing slash (/) - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-oidc.jar -``` - -Try the endpoints: - -3. Open http://localhost:7987/rest/profile in your browser. This should present - you with a response highlighting your logged in role (null) correctly as you are not logged in -4. Open `http://localhost:7987/oidc/logout` in your browser. This will log you out from your IDCS and Helidon sessions - -## Calling Sample from Postman - -Now that everything is setup it is possible to call the sample from tools like postman - -1. Create new REST call for your service , e.g. `http://localhost:7987/jersey` -2. Set authentication to oauth 2.0 -3. Press the "Get New Access Token" button - 1. Grant Type should be "Password Credentials" - 2. IDCS Access token URI should be `https://.identity.oraclecloud.com/oauth2/v1/token` - 3. ClientID and Client Secret should be obtained from IDCS and is the same that is configured in the app - 4. Scopes should be a "space" delimited list of scopes prefixed by audience , e.g. `http://localhost:7987/first_scope http://localhost:7987/second_scope` - 5. Client Authentication "Send as Basic Auth Header" -4. Request Token (If you get an error check the postman developer console) -5. Once you have a token ensure you press the "Use token" button -6. Execute your rest call - -## Troubleshooting - -#### Upon redirect to IDCS login page you receive a message indicating the scope isn't found - -- Check that *both* scope names in JerseyResource (first_scope and second_scope) exist in your IDCS application -- Check that the `primary audience` config value in IDCS contains a trailing / and the `front-end-url` in the config file does not diff --git a/examples/security/idcs-login/pom.xml b/examples/security/idcs-login/pom.xml deleted file mode 100644 index face60e5729..00000000000 --- a/examples/security/idcs-login/pom.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.security - helidon-examples-security-oidc - Helidon Security Examples IDCS Login - - - Example of login with IDCS using the OIDC provider, storing the identity in a cookie - - - - io.helidon.security.examples.idcs.IdcsMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - - io.helidon.security.providers - helidon-security-providers-oidc - - - - io.helidon.security.providers - helidon-security-providers-idcs-mapper - - - - io.helidon.security.providers - helidon-security-providers-abac - - - - io.helidon.security.abac - helidon-security-abac-scope - - - - io.helidon.security.abac - helidon-security-abac-role - - - - io.helidon.security.integration - helidon-security-integration-webserver - - - - io.helidon.config - helidon-config-encryption - - - io.helidon.config - helidon-config-yaml - - - org.jboss - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsBuilderMain.java b/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsBuilderMain.java deleted file mode 100644 index 8df4cdab19b..00000000000 --- a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsBuilderMain.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.idcs; - -import java.io.IOException; -import java.net.URI; -import java.util.Optional; - -import io.helidon.common.LogConfig; -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProvider; -import io.helidon.security.providers.oidc.OidcProvider; -import io.helidon.security.providers.oidc.OidcSupport; -import io.helidon.security.providers.oidc.common.OidcConfig; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * IDCS Login example main class using configuration . - */ -public final class IdcsBuilderMain { - private static volatile WebServer theServer; - - private IdcsBuilderMain() { - } - - public static WebServer getTheServer() { - return theServer; - } - - /** - * Start the example. - * - * @param args ignored - * @throws IOException if logging configuration fails - */ - public static void main(String[] args) throws IOException { - // load logging configuration - LogConfig.configureRuntime(); - - Config config = buildConfig(); - - OidcConfig oidcConfig = OidcConfig.builder() - .clientId("clientId.of.your.application") - .clientSecret("clientSecret.of.your.application") - .identityUri(URI.create( - "https://idcs-tenant-id.identity.oracle.com")) - //.proxyHost("proxy.proxy.com") - .frontendUri("http://your.host:your.port") - // tell us it is IDCS, so we can modify the behavior - .serverType("idcs") - .build(); - - Security security = Security.builder() - .addProvider(OidcProvider.create(oidcConfig)) - .addProvider(IdcsRoleMapperProvider.builder() - .config(config) - .oidcConfig(oidcConfig)) - .build(); - - Routing.Builder routing = Routing.builder() - .register(WebSecurity.create(security, config.get("security"))) - // IDCS requires a web resource for redirects - .register(OidcSupport.create(config)) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/rest/profile", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Response from builder based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - }); - - theServer = IdcsUtil.startIt(routing); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsMain.java b/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsMain.java deleted file mode 100644 index 73df24332ad..00000000000 --- a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsMain.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.idcs; - -import java.util.Optional; - -import io.helidon.common.LogConfig; -import io.helidon.common.context.Contexts; -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.security.providers.oidc.OidcSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * IDCS Login example main class using configuration . - */ -public final class IdcsMain { - private static volatile WebServer theServer; - - private IdcsMain() { - } - - public static WebServer getTheServer() { - return theServer; - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - Config config = buildConfig(); - - Security security = Security.create(config.get("security")); - // this is needed for proper encryption/decryption of cookies - Contexts.globalContext().register(security); - - Routing.Builder routing = Routing.builder() - .register(WebSecurity.create(security, config.get("security"))) - // IDCS requires a web resource for redirects - .register(OidcSupport.create(config)) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/rest/profile", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Response from config based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - }) - .get("/loggedout", (req, res) -> res.send("You have been logged out")); - - theServer = WebServer.create(routing, config.get("server")); - - IdcsUtil.start(theServer); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsUtil.java b/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsUtil.java deleted file mode 100644 index fcf3711be35..00000000000 --- a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/IdcsUtil.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.idcs; - -import java.net.UnknownHostException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * IDCS login example utilities. - */ -public class IdcsUtil { - // do not change this constant, unless you modify configuration - // of IDCS application redirect URI - static final int PORT = 7987; - private static final int START_TIMEOUT_SECONDS = 10; - - private IdcsUtil() { - } - - static WebServer startIt(Supplier routing) throws UnknownHostException { - return WebServer.builder(routing) - .port(PORT) - .bindAddress("localhost") - .build(); - } - - static WebServer start(WebServer webServer) { - long t = System.nanoTime(); - - CountDownLatch cdl = new CountDownLatch(1); - - webServer.start() - .thenAccept(it -> whenStarted(it, t)) - .thenRun(cdl::countDown); - - try { - cdl.await(START_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException("Failed to start server within defined timeout: " + START_TIMEOUT_SECONDS + " seconds", e); - } - - return webServer; - } - - static void whenStarted(WebServer webServer, long startNanoTime) { - long time = System.nanoTime() - startNanoTime; - - System.out.printf("Server started in %d ms%n", TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - System.out.printf("Started server on localhost:%d%n", webServer.port()); - System.out.printf("You can access this example at http://localhost:%d/rest/profile%n", webServer.port()); - System.out.println(); - System.out.println(); - System.out.println("Check application.yaml in case you are behind a proxy to configure it"); - } -} diff --git a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/package-info.java b/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/package-info.java deleted file mode 100644 index 34bfc6b52f5..00000000000 --- a/examples/security/idcs-login/src/main/java/io/helidon/security/examples/idcs/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example showcasing integration of web server with IDCS server, using Open ID Connect security provider. - * There is another example in "microprofile" directory that shows the same integration for - * a MicroProfile based application. - */ -package io.helidon.security.examples.idcs; diff --git a/examples/security/idcs-login/src/main/resources/application.yaml b/examples/security/idcs-login/src/main/resources/application.yaml deleted file mode 100644 index 0794891eaeb..00000000000 --- a/examples/security/idcs-login/src/main/resources/application.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# -# Copyright (c) 2018, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 7987 - -security: - config.require-encryption: false - properties: - # This is a nice way to be able to override this with local properties or env-vars - idcs-uri: "https://your-tenant-id.identity.oracle.com" - idcs-client-id: "your-client-id" - idcs-client-secret: "${CLEAR=your-client-secret}" - proxy-host: "" - providers: - - abac: - # Adds ABAC Provider - it does not require any configuration - - oidc: - client-id: "${security.properties.idcs-client-id}" - client-secret: "${security.properties.idcs-client-secret}" - identity-uri: "${security.properties.idcs-uri}" - # A prefix used for custom scopes - scope-audience: "http://localhost:7987/test-application" - proxy-host: "${security.properties.proxy-host}" - # Used as a base for redirects back to us (based on Host header now, so no need to explicitly define it) - # If explicitly defined, will override host header - # frontend-uri: "http://localhost:7987" - # support for non-public signature JWK (and maybe other IDCS specific handling) - server-type: "idcs" - logout-enabled: true - # Can define just a path, host will be taken from header - post-logout-uri: "/loggedout" - # We want to redirect to login page (and token can be received either through cookie or header) - redirect: true - - idcs-role-mapper: - multitenant: false - oidc-config: - # we must repeat IDCS configuration, as in this case - # IDCS serves both as open ID connect authenticator and - # as a role mapper. Using minimal configuration here - client-id: "${security.properties.idcs-client-id}" - client-secret: "${security.properties.idcs-client-secret}" - identity-uri: "${security.properties.idcs-uri}" - web-server: - # protected paths on the web server - do not include paths served by Jersey, as those are protected directly - paths: - - path: "/rest/profile" - methods: ["get"] - authenticate: true - roles-allowed: ["my_admins"] -# abac: -# scopes: ["first_scope", "second_scope"] - diff --git a/examples/security/idcs-login/src/main/resources/logging.properties b/examples/security/idcs-login/src/main/resources/logging.properties deleted file mode 100644 index 53ec2f9338a..00000000000 --- a/examples/security/idcs-login/src/main/resources/logging.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -.level=INFO -AUDIT.level=FINEST -io.helidon.security.level=FINEST - diff --git a/examples/security/jersey/README.md b/examples/security/jersey/README.md deleted file mode 100644 index 5988112eb07..00000000000 --- a/examples/security/jersey/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Security integration with Jersey - -This example demonstrates integration with Jersey (JAX-RS implementation). - -## Contents - -There are three examples with exactly the same behavior -1. builder - shows how to secure application using security built by hand -2. config - shows how to secure application with configuration - 1. see `src/main/resources/application.yaml` -3. programmatic - shows how to secure application using manual invocation of authentication - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-jersey.jar -``` - -Try the endpoints: -```bash -curl http://localhost:8080/rest -curl -v http://localhost:8080/rest/protected -curl -u "jack:password" http://localhost:8080/rest/protected -curl -u "jack:password" http://localhost:8080/rest/protected -curl -v -u "john:password" http://localhost:8080/rest/protected -``` diff --git a/examples/security/jersey/pom.xml b/examples/security/jersey/pom.xml deleted file mode 100644 index e70779d57e5..00000000000 --- a/examples/security/jersey/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-jersey - Helidon Security Examples Jersey Integration - - - Integration of security with Jersey, shows how to use configuration based approach, builder approach, and programmatic - approach. - - - - io.helidon.security.examples.jersey.JerseyConfigMain - - - - - io.helidon.security.integration - helidon-security-integration-jersey - - - io.helidon.security.integration - helidon-security-integration-jersey-client - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-jersey - - - org.glassfish.jersey.inject - jersey-hk2 - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.bundles - helidon-bundles-security - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyBuilderMain.java b/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyBuilderMain.java deleted file mode 100644 index 24939d66c65..00000000000 --- a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyBuilderMain.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.security.Security; -import io.helidon.security.integration.jersey.SecurityFeature; -import io.helidon.security.providers.abac.AbacProvider; -import io.helidon.security.providers.common.OutboundTarget; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.security.providers.httpauth.SecureUserStore; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.jersey.JerseySupport; - -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; - -/** - * Example of integration between Jersey and Security module using builders. - */ -public final class JerseyBuilderMain { - private static final Map USERS = new HashMap<>(); - private static volatile WebServer server; - - static { - addUser("jack", "password", List.of("user", "admin")); - addUser("jill", "password", List.of("user")); - addUser("john", "password", List.of()); - } - - private JerseyBuilderMain() { - } - - private static void addUser(String user, String password, List roles) { - USERS.put(user, new SecureUserStore.User() { - @Override - public String login() { - return user; - } - - private char[] password() { - return password.toCharArray(); - } - - @Override - public boolean isPasswordValid(char[] password) { - return Arrays.equals(password(), password); - } - - @Override - public Collection roles() { - return roles; - } - }); - } - - static WebServer getHttpServer() { - return server; - } - - private static SecurityFeature buildSecurity() { - return new SecurityFeature( - Security.builder() - // add the security provider to use - .addProvider(HttpBasicAuthProvider.builder() - .realm("helidon") - .userStore(users()) - .addOutboundTarget(OutboundTarget.builder("propagate-all").build())) - .addProvider(AbacProvider.create()) - .build()); - } - - private static SecureUserStore users() { - return login -> Optional.ofNullable(USERS.get(login)); - } - - private static JerseySupport buildJersey() { - return JerseySupport.builder() - // register JAX-RS resource - .register(JerseyResources.HelloWorldResource.class) - // register JAX-RS resource demonstrating identity propagation - .register(JerseyResources.OutboundSecurityResource.class) - // integrate security - .register(buildSecurity()) - .register(new ExceptionMapper() { - @Override - public Response toResponse(Exception exception) { - exception.printStackTrace(); - return Response.serverError().build(); - } - }) - .build(); - } - - /** - * Main method of example. No arguments required, no configuration required. - * - * @param args empty is OK - * @throws Throwable if server fails to start - */ - public static void main(String[] args) throws Throwable { - Routing.Builder routing = Routing.builder() - .register("/rest", buildJersey()); - - server = JerseyUtil.startIt(routing, 8080); - - JerseyResources.setPort(server.port()); - } -} diff --git a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyConfigMain.java b/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyConfigMain.java deleted file mode 100644 index 482c52d5c44..00000000000 --- a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyConfigMain.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import io.helidon.config.Config; -import io.helidon.security.Security; -import io.helidon.security.integration.jersey.SecurityFeature; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.jersey.JerseySupport; - -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; - -/** - * Example of integration between Jersey and Security module using config. - */ -public class JerseyConfigMain { - private static volatile WebServer server; - - private JerseyConfigMain() { - } - - private static SecurityFeature buildSecurity() { - Config config = Config.create().get("security"); - - Security security = Security.create(config); - - return SecurityFeature.builder(security) - .config(config.get("jersey")) - .build(); - } - - private static JerseySupport buildJersey() { - return JerseySupport.builder() - // register JAX-RS resource - .register(JerseyResources.HelloWorldResource.class) - // register JAX-RS resource demonstrating identity propagation - .register(JerseyResources.OutboundSecurityResource.class) - // integrate security - .register(buildSecurity()) - .register(new ExceptionMapper() { - @Override - public Response toResponse(Exception exception) { - if (exception instanceof WebApplicationException) { - return ((WebApplicationException) exception).getResponse(); - } - exception.printStackTrace(); - return Response.serverError().build(); - } - }) - .build(); - } - - static WebServer getHttpServer() { - return server; - } - - /** - * Main method of example. No arguments required, no configuration required. - * - * @param args empty is OK - * @throws Throwable if server fails to start - */ - public static void main(String[] args) throws Throwable { - Routing.Builder routing = Routing.builder() - .register("/rest", buildJersey()); - - server = JerseyUtil.startIt(routing, 8080); - - JerseyResources.setPort(server.port()); - } -} diff --git a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyProgrammaticMain.java b/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyProgrammaticMain.java deleted file mode 100644 index 2ca6ed82da4..00000000000 --- a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyProgrammaticMain.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import io.helidon.config.Config; -import io.helidon.security.Security; -import io.helidon.security.integration.jersey.SecurityFeature; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.jersey.JerseySupport; - -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; - -/** - * Example of integration between Jersey and Security module using config, - * yet no container security - all security enforcement is by hand. - */ -public final class JerseyProgrammaticMain { - private static volatile WebServer server; - - private JerseyProgrammaticMain() { - } - - private static SecurityFeature buildSecurity() { - return new SecurityFeature(Security.create(Config.create().get("security"))); - } - - private static JerseySupport buildJersey() { - return JerseySupport.builder() - // register JAX-RS resource - .register(JerseyResources.HelloWorldProgrammaticResource.class) - // register JAX-RS resource demonstrating identity propagation (propagation - // itself is programmatic only, this resource uses annotation to protect itself - .register(JerseyResources.OutboundSecurityResource.class) - // integrate security - .register(buildSecurity()) - .register(new ExceptionMapper() { - @Override - public Response toResponse(Exception exception) { - if (exception instanceof WebApplicationException) { - return ((WebApplicationException) exception).getResponse(); - } - exception.printStackTrace(); - return Response.serverError().build(); - } - }) - .build(); - } - - static WebServer getHttpServer() { - return server; - } - - /** - * Main method of example. No arguments required, no configuration required. - * - * @param args empty is OK - */ - public static void main(String[] args) { - Routing.Builder routing = Routing.builder() - .register("/rest", buildJersey()); - - server = JerseyUtil.startIt(routing, 8080); - - JerseyResources.setPort(server.port()); - } - -} diff --git a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyResources.java b/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyResources.java deleted file mode 100644 index 3b4e480b911..00000000000 --- a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyResources.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.SecurityContext; -import io.helidon.security.annotations.Authenticated; - -import jakarta.annotation.security.RolesAllowed; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * Resources are contained here. - */ -final class JerseyResources { - private static int port; - - private JerseyResources() { - } - - static void setPort(int port) { - JerseyResources.port = port; - } - - /** - * JAX-RS Resource. - */ - @Path("/") - public static class HelloWorldResource { - /** - * Not authenticated resource. All resources will be authorized though (to support path based authorizers, - * that may have public and protected paths). - * - * @param securityContext Security component's context - * @return Description and current subject - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String getHello(@Context SecurityContext securityContext) { - return "To test this example, call /protected. If you use a user without \"user\" role, your request will be denied. " - + "Your current subject: " + securityContext.user().orElse(SecurityContext.ANONYMOUS); - } - - /** - * Returns a hello world message and current subject. - * - * @param securityContext Security component's context - * @return returns hello and subject. - */ - //this is the important annotation for authentication to kick in - @Authenticated - @RolesAllowed("user") - @Path("/protected") - @GET - @Produces(MediaType.TEXT_PLAIN) - // due to Jersey approach to path matching, we need two methods to match both the "root" and "root" + subpaths - public String getHelloName(@Context SecurityContext securityContext) { - return "Hello, your current subject: " + securityContext.user().orElse(SecurityContext.ANONYMOUS); - } - } - - /** - * JAX-RS Resource demonstrating outbound security. - */ - @Path("/outbound") - public static class OutboundSecurityResource { - /** - * Propagates identity - will explicitly call {@link HelloWorldResource} on a URI - * that would resolve to user "tomas", but we will get the current subject... - * - * @param securityContext Security component context - * @return returns hello and subject. - */ - @Authenticated //this is the important annotation for authentication to kick in - @GET - @Produces(MediaType.TEXT_PLAIN) - public String propagateIdentity(@Context SecurityContext securityContext) { - String response = ClientBuilder.newBuilder() - .build() - .target("http://localhost:" + port + "/rest/protected") - .request() - .get(String.class); - - return "Hello, your current subject: " + securityContext.user().orElse(SecurityContext.ANONYMOUS) + "\n" - + "Response from hello world: " + response; - } - } - - /** - * JAX-RS Resource protected by hand. - */ - @Path("/") - public static class HelloWorldProgrammaticResource { - /** - * Not authenticated resource. All resources will be authorized though (to support path based authorizers, - * that may have public and protected paths). - * - * @param securityContext Security component's context - * @return Description and current subject - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String getHello(@Context SecurityContext securityContext) { - return "To test this example, call /protected. If you use a user without \"user\" role, your request will be denied. " - + "Your current subject: " + securityContext.user().orElse(SecurityContext.ANONYMOUS); - } - - /** - * Returns a hello world message and current subject. - * - * @param securityContext Security component's context - * @param headers http inbound headers - * @return returns hello and subject. - */ - @Path("/protected") - @GET - @Produces(MediaType.TEXT_PLAIN) - // due to Jersey approach to path matching, we need two methods to match both the "root" and "root" + subpaths - public Response getHelloName(@Context SecurityContext securityContext, @Context HttpHeaders headers) { - AuthenticationResponse resp = securityContext.atnClientBuilder().buildAndGet(); - - if (resp.status().isSuccess()) { - //and to authorize - // role provider can be used directly through context - if (securityContext.isUserInRole("user")) { - return Response - .ok("Hello, your current subject: " + securityContext.user().orElse(SecurityContext.ANONYMOUS)) - .build(); - } else { - return Response.status(Response.Status.FORBIDDEN).build(); - } - } - - Response.ResponseBuilder builder = Response - .status(resp.statusCode().orElse(Response.Status.UNAUTHORIZED.getStatusCode())); - - resp.responseHeaders().forEach((key, value) -> value.forEach(hv -> builder.header(key, hv))); - - return builder.build(); - } - } -} diff --git a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyUtil.java b/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyUtil.java deleted file mode 100644 index be11c5211c3..00000000000 --- a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/JerseyUtil.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Utility for this example. - */ -class JerseyUtil { - private static final int START_TIMEOUT_SECONDS = 10; - - private JerseyUtil() { - } - - static WebServer startIt(Supplier routing, int port) { - WebServer server = WebServer.builder(routing) - .port(port) - .build(); - - long t = System.nanoTime(); - - CountDownLatch cdl = new CountDownLatch(1); - - AtomicReference throwableRef = new AtomicReference<>(); - - server.start().whenComplete((webServer, throwable) -> { - if (null != throwable) { - System.err.println("Failed to start server"); - throwableRef.set(throwable); - } else { - long time = System.nanoTime() - t; - - System.out.printf("Server started in %d ms%n", TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - System.out.printf("Started server on localhost:%d%n", webServer.port()); - System.out.println(); - System.out.println("Users:"); - System.out.println("jack/password in roles: user, admin"); - System.out.println("jill/password in roles: user"); - System.out.println("john/password in no roles"); - System.out.println(); - System.out.println("***********************"); - System.out.println("** Endpoints: **"); - System.out.println("***********************"); - System.out.println("Unprotected:"); - System.out.printf(" http://localhost:%1$d/rest%n", server.port()); - System.out.println("Protected:"); - System.out.printf(" http://localhost:%1$d/rest/protected%n", server.port()); - System.out.println("Identity propagation:"); - System.out.printf(" http://localhost:%1$d/rest/outbound%n", server.port()); - } - cdl.countDown(); - }); - - try { - if (cdl.await(START_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { - Throwable thrown = throwableRef.get(); - if (null != thrown) { - throw new RuntimeException("Failed to start server", thrown); - } - } else { - throw new RuntimeException("Failed to start server, timed out"); - } - } catch (InterruptedException e) { - throw new RuntimeException("Failed to start server within defined timeout: " + START_TIMEOUT_SECONDS + " seconds"); - } - - return server; - } -} diff --git a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/package-info.java b/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/package-info.java deleted file mode 100644 index fad29b615be..00000000000 --- a/examples/security/jersey/src/main/java/io/helidon/security/examples/jersey/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of integration with Jersey. - * - * @see io.helidon.security.examples.jersey.JerseyConfigMain - * @see io.helidon.security.examples.jersey.JerseyBuilderMain - */ -package io.helidon.security.examples.jersey; diff --git a/examples/security/jersey/src/main/resources/application.yaml b/examples/security/jersey/src/main/resources/application.yaml deleted file mode 100644 index c906c0a351f..00000000000 --- a/examples/security/jersey/src/main/resources/application.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (c) 2016, 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -security: - jersey: - # Will use exceptions instead of aborting the request - this should make no difference - # to user unless you use a custom error handler - use-abort-with: false - # Will fail in case of authentication failure even if the authentication is not required. - fail-on-failure-if-optional: true - config: - # Configuration of secured config (encryption of passwords in property files) - # Set to true for production - if set to true, clear text passwords will cause failure - require-encryption: false - providers: - # Security provider - basic authentication (supports roles) - default - - http-basic-auth: - realm: "mic" - users: - - login: "jack" - password: "${CLEAR=password}" - roles: ["user", "admin"] - - login: "jill" - password: "${CLEAR=password}" - roles: ["user"] - - login: "john" - password: "${CLEAR=password}" - roles: [] - outbound: - - name: "propagate-to-all-targets" - # Security provider - ABAC (for role based authorization) - - abac: diff --git a/examples/security/jersey/src/main/resources/logging.properties b/examples/security/jersey/src/main/resources/logging.properties deleted file mode 100644 index 3f6b76d5ef0..00000000000 --- a/examples/security/jersey/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyBuilderMainTest.java b/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyBuilderMainTest.java deleted file mode 100644 index e32e12e5851..00000000000 --- a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyBuilderMainTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Test of hello world example. - */ -public class JerseyBuilderMainTest extends JerseyMainTest { - @BeforeAll - public static void initClass() throws Throwable { - JerseyBuilderMain.main(null); - } - - @AfterAll - public static void destroyClass() throws InterruptedException { - stopServer(JerseyBuilderMain.getHttpServer()); - } - - @Override - protected int getPort() { - return JerseyBuilderMain.getHttpServer().port(); - } -} diff --git a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyConfigMainTest.java b/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyConfigMainTest.java deleted file mode 100644 index 89b54d8f6e7..00000000000 --- a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyConfigMainTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Test of hello world example. - */ -public class JerseyConfigMainTest extends JerseyMainTest { - @BeforeAll - public static void initClass() throws Throwable { - JerseyConfigMain.main(null); - } - - @AfterAll - public static void destroyClass() throws InterruptedException { - stopServer(JerseyConfigMain.getHttpServer()); - } - - @Override - protected int getPort() { - return JerseyConfigMain.getHttpServer().port(); - } -} diff --git a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyMainTest.java b/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyMainTest.java deleted file mode 100644 index 83611a0ad12..00000000000 --- a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyMainTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.helidon.webserver.WebServer; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.Response; -import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.HTTP_AUTHENTICATION_PASSWORD; -import static org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.HTTP_AUTHENTICATION_USERNAME; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Common unit tests for builder, config and programmatic security. - */ -public abstract class JerseyMainTest { - private static Client client; - private static Client authFeatureClient; - - @BeforeAll - public static void classInit() { - client = ClientBuilder.newClient(); - authFeatureClient = ClientBuilder.newClient() - .register(HttpAuthenticationFeature.basicBuilder().nonPreemptive().build()); - } - - @AfterAll - public static void classDestroy() { - client.close(); - authFeatureClient.close(); - } - - static void stopServer(WebServer server) throws InterruptedException { - if (null == server) { - return; - } - CountDownLatch cdl = new CountDownLatch(1); - long t = System.nanoTime(); - server.shutdown().thenAccept(webServer -> { - long time = System.nanoTime() - t; - System.out.println("Server shutdown in " + TimeUnit.NANOSECONDS.toMillis(time) + " ms"); - cdl.countDown(); - }); - - if (!cdl.await(5, TimeUnit.SECONDS)) { - throw new IllegalStateException("Failed to shutdown server within 5 seconds"); - } - } - - @Test - public void testUnprotected() { - try (Response response = client.target(baseUri()) - .request() - .get()) { - assertThat(response.getStatus(), is(200)); - assertThat(response.readEntity(String.class), containsString("")); - } - } - - @Test - public void testProtectedOk() { - testProtected(baseUri() + "/protected", - "jack", - "password", - Set.of("user", "admin"), - Set.of()); - testProtected(baseUri() + "/protected", - "jill", - "password", - Set.of("user"), - Set.of("admin")); - } - - @Test - public void testWrongPwd() { - // here we call the endpoint - try (Response response = callProtected(baseUri() + "/protected", "jack", "somePassword")) { - assertThat(response.getStatus(), is(401)); - } - } - - @Test - public void testDenied() { - testProtectedDenied(baseUri() + "/protected", "john", "password"); - } - - @Test - public void testOutboundOk() { - testProtected(baseUri() + "/outbound", - "jill", - "password", - Set.of("user"), - Set.of("admin")); - } - - protected abstract int getPort(); - - private String baseUri() { - return "http://localhost:" + getPort() + "/rest"; - } - - private Response callProtected(String uri, String username, String password) { - // here we call the endpoint - return authFeatureClient.target(uri) - .request() - .property(HTTP_AUTHENTICATION_USERNAME, username) - .property(HTTP_AUTHENTICATION_PASSWORD, password) - .get(); - } - - private void testProtectedDenied(String uri, - String username, - String password) { - - try (Response response = callProtected(uri, username, password)) { - assertThat(response.getStatus(), is(403)); - } - } - - private void testProtected(String uri, - String username, - String password, - Set expectedRoles, - Set invalidRoles) { - - try (Response response = callProtected(uri, username, password)) { - String entity = response.readEntity(String.class); - assertThat(response.getStatus(), is(200)); - // check login - assertThat(entity, containsString("id='" + username + "'")); - // check roles - expectedRoles.forEach(role -> assertThat(entity, containsString(":" + role))); - invalidRoles.forEach(role -> assertThat(entity, not(containsString(":" + role)))); - } - } -} diff --git a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyProgrammaticMainTest.java b/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyProgrammaticMainTest.java deleted file mode 100644 index d99a93082e0..00000000000 --- a/examples/security/jersey/src/test/java/io/helidon/security/examples/jersey/JerseyProgrammaticMainTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.jersey; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Test of hello world example. - */ -public class JerseyProgrammaticMainTest extends JerseyMainTest { - @BeforeAll - public static void initClass() throws Throwable { - JerseyProgrammaticMain.main(null); - } - - @AfterAll - public static void destroyClass() throws InterruptedException { - stopServer(JerseyProgrammaticMain.getHttpServer()); - } - - @Override - protected int getPort() { - return JerseyProgrammaticMain.getHttpServer().port(); - } -} diff --git a/examples/security/nohttp-programmatic/README.md b/examples/security/nohttp-programmatic/README.md deleted file mode 100644 index 3adbea5657c..00000000000 --- a/examples/security/nohttp-programmatic/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Helidon Security Example - -Example of manually using the security APIs. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-nohttp-programmatic.jar -``` diff --git a/examples/security/nohttp-programmatic/pom.xml b/examples/security/nohttp-programmatic/pom.xml deleted file mode 100644 index 1dac1eda47b..00000000000 --- a/examples/security/nohttp-programmatic/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-nohttp-programmatic - Helidon Security Examples No-HTTP programmatic - - - Example of programmatic security without an HTTP resource. - - - - io.helidon.security.examples.security.ProgrammaticSecurity - - - - - io.helidon.security - helidon-security - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/MyProvider.java b/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/MyProvider.java deleted file mode 100644 index 5cee9d079e2..00000000000 --- a/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/MyProvider.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.security; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.List; - -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Role; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.Subject; -import io.helidon.security.spi.AuthenticationProvider; -import io.helidon.security.spi.AuthorizationProvider; -import io.helidon.security.spi.OutboundSecurityProvider; -import io.helidon.security.spi.SynchronousProvider; - -/** - * Sample provider. - */ -class MyProvider extends SynchronousProvider implements AuthenticationProvider, AuthorizationProvider, OutboundSecurityProvider { - - @Override - protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { - //get username and password - List headers = providerRequest.env().headers().getOrDefault("authorization", List.of()); - if (headers.isEmpty()) { - return AuthenticationResponse.failed("No authorization header"); - } - - String header = headers.get(0); - if (header.toLowerCase().startsWith("basic ")) { - String base64 = header.substring(6); - String unamePwd = new String(Base64.getDecoder().decode(base64), StandardCharsets.UTF_8); - int index = unamePwd.indexOf(':'); - if (index > 0) { - String name = unamePwd.substring(0, index); - String pwd = unamePwd.substring(index + 1); - if ("aUser".equals(name)) { - //authenticate - Principal principal = Principal.create(name); - Role roleGrant = Role.create("theRole"); - - Subject subject = Subject.builder() - .principal(principal) - .addGrant(roleGrant) - .addPrivateCredential(MyPrivateCreds.class, new MyPrivateCreds(name, pwd.toCharArray())) - .build(); - - return AuthenticationResponse.success(subject); - } - } - } - - return AuthenticationResponse.failed("User not found"); - } - - @Override - protected AuthorizationResponse syncAuthorize(ProviderRequest providerRequest) { - if ("CustomResourceType" - .equals(providerRequest.env().abacAttribute("resourceType").orElseThrow(() -> new IllegalArgumentException( - "Resource type is a required parameter")))) { - //supported resource - return providerRequest.securityContext() - .user() - .map(Subject::principal) - .map(Principal::getName) - .map("aUser"::equals) - .map(correct -> { - if (correct) { - return AuthorizationResponse.permit(); - } - return AuthorizationResponse.deny(); - }) - .orElse(AuthorizationResponse.deny()); - } - - return AuthorizationResponse.deny(); - } - - @Override - protected OutboundSecurityResponse syncOutbound(ProviderRequest providerRequest, - SecurityEnvironment outboundEnv, - EndpointConfig outboundEndpointConfig) { - - return providerRequest.securityContext() - .user() - .flatMap(subject -> subject.privateCredential(MyPrivateCreds.class)) - .map(myPrivateCreds -> OutboundSecurityResponse.builder() - .requestHeader("Authorization", authHeader(myPrivateCreds)) - .build() - ).orElse(OutboundSecurityResponse.abstain()); - } - - private String authHeader(MyPrivateCreds privCreds) { - String creds = privCreds.name + ":" + new String(privCreds.password); - return "basic " + Base64.getEncoder().encodeToString(creds.getBytes(StandardCharsets.UTF_8)); - } - - private static class MyPrivateCreds { - private final String name; - private final char[] password; - - private MyPrivateCreds(String name, char[] password) { - this.name = name; - this.password = password; - } - - @Override - public String toString() { - return "MyPrivateCreds: " + name; - } - } -} diff --git a/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/ProgrammaticSecurity.java b/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/ProgrammaticSecurity.java deleted file mode 100644 index f2f144c767e..00000000000 --- a/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/ProgrammaticSecurity.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.security; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.concurrent.ExecutionException; - -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; - -/** - * This class shows how to manually secure your application. - */ -public class ProgrammaticSecurity { - private static final ThreadLocal CONTEXT = new ThreadLocal<>(); - private Security security; - - /** - * Entry point to this example. - * - * @param args no needed - * @throws ExecutionException if asynchronous security fails - * @throws InterruptedException if asynchronous security gets interrupted - */ - public static void main(String[] args) throws ExecutionException, InterruptedException { - ProgrammaticSecurity instance = new ProgrammaticSecurity(); - - /* - * Simple single threaded applications - nothing too complicated - */ - //1: initialize security component - instance.init(); - //2: login - Subject subject = instance.login(); - - //3: authorize access to restricted resource - instance.execute(); - //4: propagate identity - instance.propagate(); - - /* - * More complex - multithreaded application - */ - instance.multithreaded(subject); - - } - - private static String buildBasic(String user, String password) { - return "basic " + Base64.getEncoder() - .encodeToString((user + ":" + password).getBytes(StandardCharsets.UTF_8)); - } - - private void multithreaded(Subject subject) { - Thread thread = new Thread(() -> { - try { - SecurityContext context = security.contextBuilder("newThread") - .build(); - - CONTEXT.set(context); - - //this must be done, as there is no subject (yet) for current thread (or event the login attempt may be done - //in this thread - depends on what your application wants to do... - context.runAs(subject, () -> { - //3: authorize access to restricted resource - execute(); - //4: propagate identity - propagate(); - }); - } finally { - CONTEXT.remove(); - } - }); - thread.start(); - } - - private void propagate() { - OutboundSecurityResponse response = CONTEXT.get().outboundClientBuilder().buildAndGet(); - - switch (response.status()) { - case SUCCESS: - //we should have "Authorization" header present and just need to update request headers of our outbound call - System.out.println("Authorization header: " + response.requestHeaders().get("Authorization")); - break; - case SUCCESS_FINISH: - System.out.println("Identity propagation done, request sent..."); - break; - default: - System.out.println("Failed in identity propagation provider: " + response.description().orElse(null)); - break; - } - } - - private void execute() { - SecurityContext context = CONTEXT.get(); - //check role - if (!context.isUserInRole("theRole")) { - throw new IllegalStateException("User is not in expected role"); - } - - context.env(context.env() - .derive() - .addAttribute("resourceType", "CustomResourceType")); - - //check authorization through provider - AuthorizationResponse response = context.atzClientBuilder().buildAndGet(); - - if (response.status().isSuccess()) { - //ok, process resource - System.out.println("Resource processed"); - } else { - System.out.println("You are not permitted to process resource"); - } - } - - private Subject login() { - SecurityContext securityContext = CONTEXT.get(); - securityContext.env(securityContext.env().derive() - .path("/some/path") - .header("Authorization", buildBasic("aUser", "aPassword"))); - - AuthenticationResponse response = securityContext.atnClientBuilder().buildAndGet(); - - if (response.status().isSuccess()) { - return response.user().orElseThrow(() -> new IllegalStateException("No user authenticated!")); - } - - throw new RuntimeException("Failed to authenticate", response.throwable().orElse(null)); - } - - private void init() { - //binds security context to current thread - this.security = Security.builder() - .addProvider(new MyProvider(), "FirstProvider") - .build(); - CONTEXT.set(security.contextBuilder("mainThread").build()); - } - -} diff --git a/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/package-info.java b/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/package-info.java deleted file mode 100644 index 24e45212b9b..00000000000 --- a/examples/security/nohttp-programmatic/src/main/java/io/helidon/security/examples/security/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of programmatic approach to security. - */ -package io.helidon.security.examples.security; diff --git a/examples/security/nohttp-programmatic/src/main/resources/logging.properties b/examples/security/nohttp-programmatic/src/main/resources/logging.properties deleted file mode 100644 index 3f6b76d5ef0..00000000000 --- a/examples/security/nohttp-programmatic/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/outbound-override/README.md b/examples/security/outbound-override/README.md deleted file mode 100644 index c24166f968a..00000000000 --- a/examples/security/outbound-override/README.md +++ /dev/null @@ -1,20 +0,0 @@ - -# Helidon Security Outbound Override Example - -Example that propagates identity, and on one endpoint explicitly -sets the username and password. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-outbound-override.jar -``` - -Try the endpoints: -```bash -curl -u "jack:password" http://localhost:8080/propagate -curl -u "jack:password" http://localhost:8080/override -curl -u "jill:anotherPassword" http://localhost:8080/propagate -curl -u "jill:anotherPassword" http://localhost:8080/override -``` diff --git a/examples/security/outbound-override/pom.xml b/examples/security/outbound-override/pom.xml deleted file mode 100644 index aa861ef57e2..00000000000 --- a/examples/security/outbound-override/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - 4.0.0 - helidon-examples-security-outbound-override - Helidon Security Examples Outbound Override - - - io.helidon.security.examples.outbound.OutboundOverrideExample - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.security.integration - helidon-security-integration-webserver - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.security.providers - helidon-security-providers-jwt - - - io.helidon.bundles - helidon-bundles-config - - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-security - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideExample.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideExample.java deleted file mode 100644 index 77690ff771a..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideExample.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.outbound; - -import java.util.concurrent.CompletionStage; - -import io.helidon.config.Config; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; - -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.createConfig; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.getSecurityContext; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.sendError; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.startServer; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.webTarget; - -/** - * Creates two services. First service invokes the second with outbound security. There are two endpoints - one that - * does simple identity propagation and one that uses an explicit username and password. - * - * Uses basic authentication both to authenticate users and to propagate identity. - */ -public final class OutboundOverrideExample { - private static volatile int clientPort; - private static volatile int servingPort; - - private OutboundOverrideExample() { - } - - /** - * Example that propagates identity and on one endpoint explicitly sets the username and password. - * - * @param args ignored - */ - public static void main(String[] args) { - CompletionStage first = startClientService(8080); - CompletionStage second = startServingService(9080); - - first.toCompletableFuture().join(); - second.toCompletableFuture().join(); - - System.out.println("Started services. Main endpoints:"); - System.out.println("http://localhost:" + clientPort + "/propagate"); - System.out.println("http://localhost:" + clientPort + "/override"); - System.out.println(); - System.out.println("Backend service started on:"); - System.out.println("http://localhost:" + servingPort + "/hello"); - } - - static CompletionStage startServingService(int port) { - Config config = createConfig("serving-service"); - - Routing routing = Routing.builder() - .register(WebSecurity.create(config.get("security"))) - .get("/hello", (req, res) -> { - res.send(req.context().get(SecurityContext.class).flatMap(SecurityContext::user).map( - Subject::principal).map(Principal::getName).orElse("Anonymous")); - }).build(); - return startServer(routing, port, server -> servingPort = server.port()); - } - - static CompletionStage startClientService(int port) { - Config config = createConfig("client-service"); - - Routing routing = Routing.builder() - .register(WebSecurity.create(config.get("security"))) - .get("/override", OutboundOverrideExample::override) - .get("/propagate", OutboundOverrideExample::propagate) - .build(); - return startServer(routing, port, server -> clientPort = server.port()); - } - - private static void override(ServerRequest req, ServerResponse res) { - SecurityContext context = getSecurityContext(req); - - webTarget(servingPort) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jill") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "anotherPassword") - .request(String.class) - .thenAccept(result -> res.send("You are: " + context.userName() - + ", backend service returned: " + result + "\n")) - .exceptionally(throwable -> sendError(throwable, res)); - } - - private static void propagate(ServerRequest req, ServerResponse res) { - SecurityContext context = getSecurityContext(req); - - webTarget(servingPort) - .request(String.class) - .thenAccept(result -> res.send("You are: " + context.userName() - + ", backend service returned: " + result + "\n")) - .exceptionally(throwable -> sendError(throwable, res)); - } - - static int clientPort() { - return clientPort; - } - -} diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExample.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExample.java deleted file mode 100644 index fad430c8b56..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExample.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.outbound; - -import java.util.concurrent.CompletionStage; - -import io.helidon.config.Config; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; - -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.createConfig; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.getSecurityContext; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.sendError; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.startServer; -import static io.helidon.security.examples.outbound.OutboundOverrideUtil.webTarget; - -/** - * Creates two services. First service invokes the second with outbound security. There are two endpoints - one that - * does simple identity propagation and one that uses an explicit username. - * - * Uses basic authentication to authenticate users and JWT to propagate identity. - * - * The difference between this example and basic authentication example: - *
    - *
  • Configuration files (this example uses ones with -jwt.yaml suffix)
  • - *
  • Property name used in {@link #override(ServerRequest, ServerResponse)} method to override username
  • - *
- */ -public final class OutboundOverrideJwtExample { - private static volatile int clientPort; - private static volatile int servingPort; - - private OutboundOverrideJwtExample() { - } - - /** - * Example that propagates identity and on one endpoint explicitly sets the username and password. - * - * @param args ignored - */ - public static void main(String[] args) { - CompletionStage first = startClientService(8080); - CompletionStage second = startServingService(9080); - - first.toCompletableFuture().join(); - second.toCompletableFuture().join(); - - System.out.println("Started services. Main endpoints:"); - System.out.println("http://localhost:" + clientPort + "/propagate"); - System.out.println("http://localhost:" + clientPort + "/override"); - System.out.println(); - System.out.println("Backend service started on:"); - System.out.println("http://localhost:" + servingPort + "/hello"); - } - - static CompletionStage startServingService(int port) { - Config config = createConfig("serving-service-jwt"); - - Routing routing = Routing.builder() - .register(WebSecurity.create(config.get("security"))) - .get("/hello", (req, res) -> { - // This is the token. It should be bearer - req.headers().first("Authorization") - .ifPresent(System.out::println); - res.send(req.context().get(SecurityContext.class).flatMap(SecurityContext::user).map( - Subject::principal).map(Principal::getName).orElse("Anonymous")); - }).build(); - return startServer(routing, port, server -> servingPort = server.port()); - } - - static CompletionStage startClientService(int port) { - Config config = createConfig("client-service-jwt"); - - Routing routing = Routing.builder() - .register(WebSecurity.create(config.get("security"))) - .get("/override", OutboundOverrideJwtExample::override) - .get("/propagate", OutboundOverrideJwtExample::propagate) - .build(); - return startServer(routing, port, server -> clientPort = server.port()); - } - - private static void override(ServerRequest req, ServerResponse res) { - SecurityContext context = getSecurityContext(req); - - webTarget(servingPort) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jill") - .request(String.class) - .thenAccept(result -> res.send("You are: " + context.userName() + ", backend service returned: " + result)) - .exceptionally(throwable -> sendError(throwable, res)); - } - - private static void propagate(ServerRequest req, ServerResponse res) { - SecurityContext context = getSecurityContext(req); - - webTarget(servingPort) - .request(String.class) - .thenAccept(result -> res.send("You are: " + context.userName() + ", backend service returned: " + result)) - .exceptionally(throwable -> sendError(throwable, res)); - } - - static int clientPort() { - return clientPort; - } -} diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideUtil.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideUtil.java deleted file mode 100644 index b253b16c278..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideUtil.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.outbound; - -import java.util.concurrent.CompletionStage; -import java.util.function.Consumer; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.security.SecurityContext; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientRequestBuilder; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.WebServer; - -/** - * Example utilities. - */ -public final class OutboundOverrideUtil { - private static final WebClient CLIENT = WebClient.builder() - .addService(WebClientSecurity.create()) - .build(); - - private OutboundOverrideUtil() { - } - - static WebClientRequestBuilder webTarget(int port) { - return CLIENT.get() - .uri("http://localhost:" + port + "/hello"); - } - - static Void sendError(Throwable throwable, ServerResponse res) { - res.status(Http.Status.INTERNAL_SERVER_ERROR_500); - res.send("Error: " + throwable.getClass().getName() + ": " + throwable.getMessage()); - return null; - } - - static Config createConfig(String fileName) { - return Config.builder() - .sources(ConfigSources.classpath(fileName + ".yaml")) - .build(); - } - - static SecurityContext getSecurityContext(ServerRequest req) { - return req.context().get(SecurityContext.class) - .orElseThrow(() -> new RuntimeException("Failed to get security context from request, security not configured")); - } - - static CompletionStage startServer(Routing routing, int port, Consumer callback) { - return WebServer.builder(routing) - .port(port) - .build() - .start() - .thenAccept(callback); - } -} diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/package-info.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/package-info.java deleted file mode 100644 index 230eebf33fd..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example to show how to override default settings of an outbound provider. - */ -package io.helidon.security.examples.outbound; diff --git a/examples/security/outbound-override/src/main/resources/client-service-jwt.yaml b/examples/security/outbound-override/src/main/resources/client-service-jwt.yaml deleted file mode 100644 index 9661c20a1b4..00000000000 --- a/examples/security/outbound-override/src/main/resources/client-service-jwt.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -security: - provider-policy: - type: "COMPOSITE" - authentication: - - name: "http-basic-auth" - outbound: - - name: "jwt" - providers: - - http-basic-auth: - users: - - login: "john" - password: "johnnyPassword" - roles: ["admin"] - - login: "jack" - password: "password" - roles: ["user", "admin"] - - login: "jill" - password: "anotherPassword" - roles: ["user"] - - jwt: - allow-impersonation: true - atn-token: - # we are not interested in inbound tokens - verify-signature: false - sign-token: - jwk.resource.resource-path: "signing-jwk.json" - jwt-issuer: "example.helidon.io" - outbound: - - name: "propagate-identity" - jwk-kid: "example" - jwt-kid: "helidon" - jwt-audience: "http://example.helidon.io" - outbound-token: - header: "Authorization" - format: "bearer %1$s" - outbound: - - name: "propagate-all" - web-server: - defaults: - authenticate: true - paths: - - path: "/propagate" - methods: ["get"] - roles-allowed: "user" - - path: "/override" - methods: ["get"] - roles-allowed: "user" \ No newline at end of file diff --git a/examples/security/outbound-override/src/main/resources/client-service.yaml b/examples/security/outbound-override/src/main/resources/client-service.yaml deleted file mode 100644 index 94b3924f9fb..00000000000 --- a/examples/security/outbound-override/src/main/resources/client-service.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -security: - providers: - - http-basic-auth: - users: - - login: "john" - password: "johnnyPassword" - roles: ["admin"] - - login: "jack" - password: "password" - roles: ["user", "admin"] - - login: "jill" - password: "anotherPassword" - roles: ["user"] - outbound: - - name: "propagate-all" - web-server: - defaults: - authenticate: true - paths: - - path: "/propagate" - methods: ["get"] - roles-allowed: "user" - - path: "/override" - methods: ["get"] - roles-allowed: "user" \ No newline at end of file diff --git a/examples/security/outbound-override/src/main/resources/serving-service-jwt.yaml b/examples/security/outbound-override/src/main/resources/serving-service-jwt.yaml deleted file mode 100644 index 73df14d5cd2..00000000000 --- a/examples/security/outbound-override/src/main/resources/serving-service-jwt.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -security: - providers: - - jwt: - atn-token: - jwk.resource.resource-path: "verifying-jwk.json" - jwt-audience: "http://example.helidon.io" - web-server: - defaults: - authenticate: true - paths: - - path: "/hello" - methods: ["get"] diff --git a/examples/security/outbound-override/src/main/resources/serving-service.yaml b/examples/security/outbound-override/src/main/resources/serving-service.yaml deleted file mode 100644 index 089ccf36b83..00000000000 --- a/examples/security/outbound-override/src/main/resources/serving-service.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -security: - providers: - - http-basic-auth: - users: - - login: "jack" - password: "password" - roles: ["user", "admin"] - - login: "jill" - password: "anotherPassword" - roles: ["user"] - web-server: - defaults: - authenticate: true - paths: - - path: "/hello" - methods: ["get"] - roles-allowed: "user" diff --git a/examples/security/outbound-override/src/main/resources/signing-jwk.json b/examples/security/outbound-override/src/main/resources/signing-jwk.json deleted file mode 100644 index 09df45ed5b0..00000000000 --- a/examples/security/outbound-override/src/main/resources/signing-jwk.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "keys": [ - { - "kty": "oct", - "kid": "example", - "alg": "HS256", - "key_ops": [ - "sign", - "verify" - ], - "k": "FdFYFzERwC2uCBB46pZQi4GG85LujR8obt-KWRBICVQ" - } - ] -} \ No newline at end of file diff --git a/examples/security/outbound-override/src/main/resources/verifying-jwk.json b/examples/security/outbound-override/src/main/resources/verifying-jwk.json deleted file mode 100644 index 5bfc903024a..00000000000 --- a/examples/security/outbound-override/src/main/resources/verifying-jwk.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "keys": [ - { - "kty": "oct", - "kid": "helidon", - "alg": "HS256", - "key_ops": [ - "sign", - "verify" - ], - "k": "FdFYFzERwC2uCBB46pZQi4GG85LujR8obt-KWRBICVQ" - } - ] -} \ No newline at end of file diff --git a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideExampleTest.java b/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideExampleTest.java deleted file mode 100644 index a38498fa4cc..00000000000 --- a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideExampleTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.outbound; - -import java.util.concurrent.CompletionStage; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.security.WebClientSecurity; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.security.examples.outbound.OutboundOverrideExample.clientPort; -import static io.helidon.security.examples.outbound.OutboundOverrideExample.startClientService; -import static io.helidon.security.examples.outbound.OutboundOverrideExample.startServingService; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -/** - * Test of security override example. - */ -public class OutboundOverrideExampleTest { - - private static WebClient webClient; - - @BeforeAll - public static void setup() { - CompletionStage first = startClientService(-1); - CompletionStage second = startServingService(-1); - - first.toCompletableFuture().join(); - second.toCompletableFuture().join(); - - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.builder().build()) - .build(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + clientPort()) - .addService(WebClientSecurity.create(security)) - .build(); - } - - @Test - public void testOverrideExample() { - String value = webClient.get() - .path("/override") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "password") - .request(String.class) - .await(); - - assertThat(value, is("You are: jack, backend service returned: jill\n")); - } - - @Test - public void testPropagateExample() { - String value = webClient.get() - .path("/propagate") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "password") - .request(String.class) - .await(); - - assertThat(value, is("You are: jack, backend service returned: jack\n")); - } - -} diff --git a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExampleTest.java b/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExampleTest.java deleted file mode 100644 index bddf6d1cf58..00000000000 --- a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExampleTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.security.examples.outbound; - -import java.util.concurrent.CompletionStage; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.security.WebClientSecurity; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.security.examples.outbound.OutboundOverrideJwtExample.clientPort; -import static io.helidon.security.examples.outbound.OutboundOverrideJwtExample.startClientService; -import static io.helidon.security.examples.outbound.OutboundOverrideJwtExample.startServingService; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -/** - * Test of security override example. - */ -public class OutboundOverrideJwtExampleTest { - - private static WebClient webClient; - - @BeforeAll - public static void setup() { - CompletionStage first = startClientService(-1); - CompletionStage second = startServingService(-1); - - first.toCompletableFuture().join(); - second.toCompletableFuture().join(); - - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.builder().build()) - .build(); - - webClient = WebClient.builder() - .baseUri("http://localhost:" + clientPort()) - .addService(WebClientSecurity.create(security)) - .build(); - } - - @Test - public void testOverrideExample() { - String value = webClient.get() - .path("/override") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "password") - .request(String.class) - .await(); - - assertThat(value, is("You are: jack, backend service returned: jill")); - } - - @Test - public void testPropagateExample() { - String value = webClient.get() - .path("/propagate") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "password") - .request(String.class) - .await(); - - assertThat(value, is("You are: jack, backend service returned: jack")); - } - -} diff --git a/examples/security/pom.xml b/examples/security/pom.xml deleted file mode 100644 index 52998574ee4..00000000000 --- a/examples/security/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.security - helidon-examples-security-project - Helidon Security Examples - pom - - - Examples of Helidon Security usage and integrations - - - - nohttp-programmatic - jersey - webserver-digest-auth - webserver-signatures - google-login - spi-examples - attribute-based-access-control - idcs-login - outbound-override - basic-auth-with-static-content - vaults - - diff --git a/examples/security/spi-examples/README.md b/examples/security/spi-examples/README.md deleted file mode 100644 index 15652fc7aa4..00000000000 --- a/examples/security/spi-examples/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# SPI implementation - -This example demonstrates how to implement various SPIs of security component. - -Contents --------- -The following examples are available: -1. Authentication provider -2. Authorization provider -3. Outbound provider -3. Audit provider -4. Provider selection policy - -# Running the Example - -This is an API/SPI example. It is validated through unit tests. - \ No newline at end of file diff --git a/examples/security/spi-examples/pom.xml b/examples/security/spi-examples/pom.xml deleted file mode 100644 index 78074621fd8..00000000000 --- a/examples/security/spi-examples/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-spi - Helidon Security Examples SPI Implementation - - - Example of implementation of custom providers and other SPI implementations - - - - 2.23.4 - - - - - io.helidon.security - helidon-security - - - io.helidon.bundles - helidon-bundles-config - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - org.mockito - mockito-core - ${version.lib.mockito} - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtnProviderSync.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtnProviderSync.java deleted file mode 100644 index 2e62051d7ca..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtnProviderSync.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import io.helidon.config.Config; -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Role; -import io.helidon.security.SecurityLevel; -import io.helidon.security.Subject; -import io.helidon.security.spi.AuthenticationProvider; -import io.helidon.security.spi.SynchronousProvider; - -/** - * Example of an authentication provider implementation - synchronous. - * This is a full-blows example of a provider that requires additional configuration on a resource. - */ -public class AtnProviderSync extends SynchronousProvider implements AuthenticationProvider { - @Override - protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { - - // first obtain the configuration of this request - // either from annotation, custom object or config - AtnObject myObject = getCustomObject(providerRequest.endpointConfig()); - - if (null == myObject) { - // I do not have my required information, this request is probably not for me - return AuthenticationResponse.abstain(); - } - - if (myObject.isValid()) { - // now authenticate - this example just creates a subject - // based on the value (user subject) and size (group subject) - return AuthenticationResponse.success(Subject.builder() - .addPrincipal(Principal.create(myObject.getValue())) - .addGrant(Role.create("role_" + myObject.getSize())) - .build()); - } else { - return AuthenticationResponse.failed("Invalid request"); - } - } - - private AtnObject getCustomObject(EndpointConfig epConfig) { - // order I choose - this depends on type of security you implement and your choice: - // 1) custom object in request (as this must be explicitly done by a developer) - Optional opt = epConfig.instance(AtnObject.class); - if (opt.isPresent()) { - return opt.get(); - } - - // 2) configuration in request - opt = epConfig.config("atn-object").flatMap(conf -> conf.as(AtnObject::from).asOptional()); - if (opt.isPresent()) { - return opt.get(); - } - - // 3) annotations on target - List annots = new ArrayList<>(); - for (SecurityLevel securityLevel : epConfig.securityLevels()) { - annots.addAll(securityLevel.combineAnnotations(AtnAnnot.class, EndpointConfig.AnnotationScope.values())); - } - if (annots.isEmpty()) { - return null; - } else { - return AtnObject.from(annots.get(0)); - } - } - - @Override - public Collection> supportedAnnotations() { - return Set.of(AtnAnnot.class); - } - - /** - * This is an example annotation to see how to work with them. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD}) - @Documented - public @interface AtnAnnot { - /** - * This is an example value. - * - * @return some value - */ - String value(); - - /** - * This is an example value. - * - * @return some size - */ - int size() default 4; - } - - /** - * This is an example custom object. - * Also acts as an object to get configuration in config. - */ - public static class AtnObject { - private String value; - private int size = 4; - - /** - * Load this object instance from configuration. - * - * @param config configuration - * @return a new instance - */ - public static AtnObject from(Config config) { - AtnObject result = new AtnObject(); - config.get("value").asString().ifPresent(result::setValue); - config.get("size").asInt().ifPresent(result::setSize); - return result; - } - - static AtnObject from(AtnAnnot annot) { - AtnObject result = new AtnObject(); - result.setValue(annot.value()); - result.setSize(annot.size()); - return result; - } - - static AtnObject from(String value, int size) { - AtnObject result = new AtnObject(); - result.setValue(value); - result.setSize(size); - return result; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public int getSize() { - return size; - } - - public void setSize(int size) { - this.size = size; - } - - public boolean isValid() { - return null != value; - } - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtzProviderSync.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtzProviderSync.java deleted file mode 100644 index 0423efea736..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtzProviderSync.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.ProviderRequest; -import io.helidon.security.spi.AuthorizationProvider; -import io.helidon.security.spi.SynchronousProvider; - -/** - * Authorization provider example. The most simplistic approach. - * - * @see AtnProviderSync on how to use custom objects, config and annotations in a provider - */ -public class AtzProviderSync extends SynchronousProvider implements AuthorizationProvider { - @Override - protected AuthorizationResponse syncAuthorize(ProviderRequest providerRequest) { - // just check the path contains the string "public", otherwise allow only if user is logged in - // if no path is defined, abstain (e.g. I do not care about such requests - I can neither allow or deny them) - return providerRequest.env().path() - .map(path -> { - if (path.contains("public")) { - return AuthorizationResponse.permit(); - } - if (providerRequest.securityContext().isAuthenticated()) { - return AuthorizationResponse.permit(); - } else { - return AuthorizationResponse.deny(); - } - }).orElse(AuthorizationResponse.abstain()); - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/Auditer.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/Auditer.java deleted file mode 100644 index d5f0fc261a4..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/Auditer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import java.util.LinkedList; -import java.util.List; -import java.util.function.Consumer; - -import io.helidon.security.spi.AuditProvider; - -/** - * Audit provider implementation. - */ -public class Auditer implements AuditProvider { - // BEWARE this is a memory leak. Only for example purposes and for unit-tests - private final List messages = new LinkedList<>(); - - public List getMessages() { - return messages; - } - - @Override - public Consumer auditConsumer() { - return event -> { - // just dump to stdout and store in a list - System.out.println(event.severity() + ": " + event.tracingId() + ": " + event); - messages.add(event); - }; - } - -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/OutboundProviderSync.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/OutboundProviderSync.java deleted file mode 100644 index f0590667fb4..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/OutboundProviderSync.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import java.util.List; -import java.util.Map; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.Subject; -import io.helidon.security.spi.OutboundSecurityProvider; -import io.helidon.security.spi.SynchronousProvider; - -/** - * Example of a simplistic outbound security provider. - */ -public class OutboundProviderSync extends SynchronousProvider implements OutboundSecurityProvider { - @Override - protected OutboundSecurityResponse syncOutbound(ProviderRequest providerRequest, - SecurityEnvironment outboundEnv, - EndpointConfig outboundEndpointConfig) { - - // let's just add current user's id as a custom header, otherwise do nothing - return providerRequest.securityContext() - .user() - .map(Subject::principal) - .map(Principal::getName) - .map(name -> OutboundSecurityResponse - .withHeaders(Map.of("X-AUTH-USER", List.of(name)))) - .orElse(OutboundSecurityResponse.abstain()); - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/ProviderSelector.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/ProviderSelector.java deleted file mode 100644 index 7c26e04d9e1..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/ProviderSelector.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; - -import io.helidon.security.NamedProvider; -import io.helidon.security.spi.OutboundSecurityProvider; -import io.helidon.security.spi.ProviderSelectionPolicy; -import io.helidon.security.spi.SecurityProvider; - -/** - * Simple selector of providers, just chooses first, except for outbound, where it returns all. - */ -public class ProviderSelector implements ProviderSelectionPolicy { - private final Providers providers; - private final List outboundProviders = new LinkedList<>(); - - private ProviderSelector(Providers providers) { - this.providers = providers; - - providers.getProviders(OutboundSecurityProvider.class) - .forEach(np -> outboundProviders.add(np.getProvider())); - } - - /** - * This is the function to register with security. - * - * @param providers Providers from security - * @return selector instance - * @see io.helidon.security.Security.Builder#providerSelectionPolicy(java.util.function.Function) - */ - public static ProviderSelector create(Providers providers) { - return new ProviderSelector(providers); - } - - @Override - public Optional selectProvider(Class providerType) { - List> providers = this.providers.getProviders(providerType); - - if (providers.isEmpty()) { - return Optional.empty(); - } else { - return Optional.of(providers.get(0).getProvider()); - } - } - - @Override - public List selectOutboundProviders() { - return outboundProviders; - } - - @Override - public Optional selectProvider(Class providerType, String requestedName) { - return this.providers.getProviders(providerType) - .stream() - .filter(provider -> provider.getName().equals(requestedName)) - .findFirst() - .map(NamedProvider::getProvider); - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/package-info.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/package-info.java deleted file mode 100644 index c7ac4119d87..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Examples of SPI implementation. - * - * @see io.helidon.security.spi.AuthenticationProvider - */ -package io.helidon.security.examples.spi; diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtnProviderSyncTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtnProviderSyncTest.java deleted file mode 100644 index 7bc45249f14..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtnProviderSyncTest.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2018, 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.security.examples.spi; - -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.SecurityLevel; -import io.helidon.security.SecurityResponse; -import io.helidon.security.Subject; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Unit test for {@link AtnProviderSync}. - */ -public class AtnProviderSyncTest { - private static final String VALUE = "aValue"; - private static final int SIZE = 16; - - @Test - public void testAbstain() { - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtnProviderSync provider = new AtnProviderSync(); - - AuthenticationResponse response = provider.syncAuthenticate(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.ABSTAIN)); - } - - @Test - public void testAnnotationSuccess() { - AtnProviderSync.AtnAnnot annot = new AtnProviderSync.AtnAnnot() { - @Override - public String value() { - return VALUE; - } - - @Override - public int size() { - return SIZE; - } - - @Override - public Class annotationType() { - return AtnProviderSync.AtnAnnot.class; - } - }; - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - - SecurityLevel level = SecurityLevel.create("mock") - .withClassAnnotations(Map.of(AtnProviderSync.AtnAnnot.class, List.of(annot))) - .build(); - - EndpointConfig ep = EndpointConfig.builder() - .securityLevels(List.of(level)) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - testSuccess(request); - } - - @Test - public void testCustomObjectSuccess() { - AtnProviderSync.AtnObject obj = new AtnProviderSync.AtnObject(); - obj.setSize(SIZE); - obj.setValue(VALUE); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.builder() - .customObject(AtnProviderSync.AtnObject.class, obj) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - testSuccess(request); - } - - @Test - public void testConfigSuccess() { - Config config = Config.create( - ConfigSources.create(Map.of("value", VALUE, - "size", String.valueOf(SIZE))) - ); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.builder() - .config("atn-object", config) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - - testSuccess(request); - } - - @Test - public void testFailure() { - Config config = Config.create( - ConfigSources.create(Map.of("atn-object.size", String.valueOf(SIZE))) - ); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.builder() - .config("atn-object", config) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtnProviderSync provider = new AtnProviderSync(); - - AuthenticationResponse response = provider.syncAuthenticate(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.FAILURE)); - } - - @Test - public void integrationTest() { - Security security = Security.builder() - .addProvider(new AtnProviderSync()) - .build(); - - // this part is usually done by container integration component - // in Jersey you have access to security context through annotations - // in Web server you have access to security context through context - SecurityContext context = security.createContext("unit-test"); - context.endpointConfig(EndpointConfig.builder() - .customObject(AtnProviderSync.AtnObject.class, - AtnProviderSync.AtnObject.from(VALUE, SIZE))); - AuthenticationResponse response = context.authenticate(); - - validateResponse(response); - } - - private void validateResponse(AuthenticationResponse response) { - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - Optional maybeuser = response.user(); - - maybeuser.ifPresentOrElse(user -> { - assertThat(user.principal().id(), is(VALUE)); - Set roles = Security.getRoles(user); - assertThat(roles.size(), is(1)); - assertThat(roles.iterator().next(), is("role_" + SIZE)); - }, () -> fail("User should have been returned")); - } - - private void testSuccess(ProviderRequest request) { - AtnProviderSync provider = new AtnProviderSync(); - - AuthenticationResponse response = provider.syncAuthenticate(request); - validateResponse(response); - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtzProviderSyncTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtzProviderSyncTest.java deleted file mode 100644 index 194f6ab1e97..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtzProviderSyncTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.ProviderRequest; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.SecurityResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Unit test for {@link AtzProviderSync}. - */ -public class AtzProviderSyncTest { - @Test - public void testPublic() { - SecurityEnvironment se = SecurityEnvironment.builder() - .path("/public/some/path") - .build(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.syncAuthorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - } - - @Test - public void testAbstain() { - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.syncAuthorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.ABSTAIN)); - } - - @Test - public void testDenied() { - SecurityContext context = mock(SecurityContext.class); - when(context.isAuthenticated()).thenReturn(false); - - SecurityEnvironment se = SecurityEnvironment.builder() - .path("/private/some/path") - .build(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.syncAuthorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.FAILURE)); - } - - @Test - public void testPermitted() { - SecurityContext context = mock(SecurityContext.class); - when(context.isAuthenticated()).thenReturn(true); - - SecurityEnvironment se = SecurityEnvironment.builder() - .path("/private/some/path") - .build(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.syncAuthorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AuditerTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AuditerTest.java deleted file mode 100644 index 8ff42efbef8..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AuditerTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import java.util.List; -import java.util.stream.Collectors; - -import io.helidon.security.AuditEvent; -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.spi.AuditProvider; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Unit test for {@link Auditer}. - */ -public class AuditerTest { - @Test - public void integrateIt() throws InterruptedException { - Auditer auditer = new Auditer(); - - Security sec = Security.builder() - .addAuthorizationProvider(new AtzProviderSync()) - .addAuditProvider(auditer) - .build(); - - SecurityContext context = sec.createContext("unit-test"); - context.env(SecurityEnvironment.builder() - .path("/public/path")); - - AuthorizationResponse response = context.authorize(); - - // as auditing is asynchronous, we must give it some time to process - Thread.sleep(100); - - List messages = auditer.getMessages(); - // there should be two messages - configuration of security and authorization - - List atzEvents = messages.stream() - .filter(event -> event.eventType().startsWith(AuditEvent.AUTHZ_TYPE_PREFIX)) - .collect(Collectors.toList()); - - assertThat("We only expect a single authorization event", atzEvents.size(), is(1)); - - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/OutboundProviderSyncTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/OutboundProviderSyncTest.java deleted file mode 100644 index 24acd24c221..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/OutboundProviderSyncTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import java.util.List; -import java.util.Optional; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.SecurityResponse; -import io.helidon.security.Subject; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Unit test for {@link OutboundProviderSync}. - */ -public class OutboundProviderSyncTest { - @Test - public void testAbstain() { - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - - OutboundProviderSync ops = new OutboundProviderSync(); - OutboundSecurityResponse response = ops.syncOutbound(request, SecurityEnvironment.create(), EndpointConfig.create()); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.ABSTAIN)); - } - - @Test - public void testSuccess() { - String username = "aUser"; - Subject subject = Subject.create(Principal.create(username)); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.of(subject)); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - - OutboundProviderSync ops = new OutboundProviderSync(); - OutboundSecurityResponse response = ops.syncOutbound(request, SecurityEnvironment.create(), EndpointConfig.create()); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - assertThat(response.requestHeaders().get("X-AUTH-USER"), is(List.of(username))); - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/ProviderSelectorTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/ProviderSelectorTest.java deleted file mode 100644 index 243a4a6ba42..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/ProviderSelectorTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.spi; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; - -import org.junit.jupiter.api.Test; - -/** - * Unit test for {@link ProviderSelector}. - */ -public class ProviderSelectorTest { - @Test - public void integrateIt() { - Security security = Security.builder() - .providerSelectionPolicy(ProviderSelector::create) - .addProvider(new AtnProviderSync()) - .addProvider(new AtzProviderSync()) - .build(); - - SecurityContext context = security.createContext("unit-test"); - context.env(SecurityEnvironment.builder().path("/public/path")); - - AuthorizationResponse response = context.authorize(); - - // if we reached here, the policy worked - } -} diff --git a/examples/security/vaults/README.md b/examples/security/vaults/README.md deleted file mode 100644 index 6ee954528ca..00000000000 --- a/examples/security/vaults/README.md +++ /dev/null @@ -1,34 +0,0 @@ -Vaults example ----- - -This example demonstrates the use of `Security` to: -- access secrets -- generate digests (such as Signatures and HMAC) -- verify digests (dtto) -- encrypt secret text -- decrypt cipher text - -The example uses three implementations of security providers that implement these features: - -1. OCI Vault provider (supports all) -2. Config provider (supports encryption/decryption and secrets) -3. Hashicorp (HCP) Vault provider (supports all + HMAC digest) - - -# OCI Vault - -The following information/configuration is needed: - -1. `~/.oci/config` file should be present (TODO link to description how to get it) -2. A secret (for password) must be created and its OCID configured in `${oci.properties.secret-ocid}` -3. An RSA key must be created and its OCID configured in `${oci.properties.vault-rsa-key-ocid}` for signature -4. Key must be created and its OCID configured in `${oci.properties.vault-key-ocid}` for encryption - -# HCP Vault - -1. Vault address must be defined in `vault.address` -2. Vault token must be defined in `vault.token` -3. A secret must be defined in the default secrets under path `app/secret` with key `username` defining a user -4. Vault `transit` secret engine must be enabled -5. A key named `signature-key` must be created (RSA) in `transit` secret engine for signature -6. A key named `encryption-key` must be created in `transit` secret engine for encryption and HMAC diff --git a/examples/security/vaults/pom.xml b/examples/security/vaults/pom.xml deleted file mode 100644 index 1c98b9c7616..00000000000 --- a/examples/security/vaults/pom.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-vaults - Helidon Security Examples Vaults - - - This example demonstrates usage of vault implementations - OCI, Hashicorp Vault, and Config based vault - - - - io.helidon.examples.security.vaults.VaultsExampleMain - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security - helidon-security - - - io.helidon.security.providers - helidon-security-providers-config-vault - - - io.helidon.webserver - helidon-webserver - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv2 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-transit - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-token - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/DigestService.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/DigestService.java deleted file mode 100644 index 322efb4379d..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/DigestService.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.security.vaults; - -import java.nio.charset.StandardCharsets; - -import io.helidon.security.Security; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -class DigestService implements Service { - private final Security security; - - DigestService(Security security) { - this.security = security; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/digest/{config}/{text}", this::digest) - .get("/verify/{config}/{text}/{digest:.*}", this::verify); - } - - private void digest(ServerRequest req, ServerResponse res) { - String configName = req.path().param("config"); - String text = req.path().param("text"); - - security.digest(configName, text.getBytes(StandardCharsets.UTF_8)) - .forSingle(res::send) - .exceptionally(res::send); - } - - private void verify(ServerRequest req, ServerResponse res) { - String configName = req.path().param("config"); - String text = req.path().param("text"); - String digest = req.path().param("digest"); - - security.verifyDigest(configName, text.getBytes(StandardCharsets.UTF_8), digest) - .map(it -> it ? "Valid" : "Invalid") - .forSingle(res::send) - .exceptionally(res::send); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/EncryptionService.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/EncryptionService.java deleted file mode 100644 index ea544fd6fcc..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/EncryptionService.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.security.vaults; - -import java.nio.charset.StandardCharsets; - -import io.helidon.security.Security; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -class EncryptionService implements Service { - private final Security security; - - EncryptionService(Security security) { - this.security = security; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/encrypt/{config}/{text:.*}", this::encrypt) - .get("/decrypt/{config}/{cipherText:.*}", this::decrypt); - } - - private void encrypt(ServerRequest req, ServerResponse res) { - String configName = req.path().param("config"); - String text = req.path().param("text"); - - security.encrypt(configName, text.getBytes(StandardCharsets.UTF_8)) - .forSingle(res::send) - .exceptionally(res::send); - } - - private void decrypt(ServerRequest req, ServerResponse res) { - String configName = req.path().param("config"); - String cipherText = req.path().param("cipherText"); - - security.decrypt(configName, cipherText) - .forSingle(res::send) - .exceptionally(res::send); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/SecretsService.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/SecretsService.java deleted file mode 100644 index 79fdabd40d2..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/SecretsService.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.security.vaults; - -import io.helidon.security.Security; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -class SecretsService implements Service { - private final Security security; - - SecretsService(Security security) { - this.security = security; - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/{name}", this::secret); - } - - private void secret(ServerRequest req, ServerResponse res) { - String secretName = req.path().param("name"); - security.secret(secretName, "default-" + secretName) - .forSingle(res::send) - .exceptionally(res::send); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/VaultsExampleMain.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/VaultsExampleMain.java deleted file mode 100644 index 77dac8fcc23..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/VaultsExampleMain.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.security.vaults; - -import java.util.concurrent.TimeUnit; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.security.Security; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of the example based on configuration. - */ -public final class VaultsExampleMain { - private VaultsExampleMain() { - } - - /** - * Start the server. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - // as I cannot share my configuration of OCI, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - System.out.println("This example requires a valid OCI Vault, Secret and keys configured. It also requires " - + "a Hashicorp Vault running with preconfigured data. Please see README.md"); - - Security security = Security.create(config.get("security")); - - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(Routing.builder() - .register("/secrets", new SecretsService(security)) - .register("/encryption", new EncryptionService(security)) - .register("/digests", new DigestService(security))) - .build() - .start() - .await(10, TimeUnit.SECONDS); - - System.out.println("Server started on port: " + server.port()); - String baseAddress = "http://localhost:" + server.port() + "/"; - - System.out.println("Secrets endpoints:"); - System.out.println(); - System.out.println("OCI secret:"); - System.out.println("\t" + baseAddress + "secrets/password"); - System.out.println("Config secret:"); - System.out.println("\t" + baseAddress + "secrets/token"); - System.out.println("HCP Vault secret:"); - System.out.println("\t" + baseAddress + "secrets/username"); - System.out.println(); - - System.out.println("Encryption endpoints:"); - System.out.println("OCI encrypted:"); - System.out.println("\t" + baseAddress + "encryption/encrypt/crypto-1/text"); - System.out.println("\t" + baseAddress + "encryption/decrypt/crypto-1/cipherText"); - System.out.println("Config encrypted:"); - System.out.println("\t" + baseAddress + "encryption/encrypt/crypto-2/text"); - System.out.println("\t" + baseAddress + "encryption/decrypt/crypto-2/cipherText"); - System.out.println("HCP Vault encrypted:"); - System.out.println("\t" + baseAddress + "encryption/encrypt/crypto-3/text"); - System.out.println("\t" + baseAddress + "encryption/decrypt/crypto-3/cipherText"); - System.out.println(); - - System.out.println("Signature/HMAC endpoints:"); - System.out.println("OCI Signature:"); - System.out.println("\t" + baseAddress + "digests/digest/sig-1/text"); - System.out.println("\t" + baseAddress + "digests/verify/sig-1/text/signature"); - System.out.println("HCP Vault Signature:"); - System.out.println("\t" + baseAddress + "digests/digest/sig-2/text"); - System.out.println("\t" + baseAddress + "digests/digest/sig-2/text/signature"); - System.out.println("HCP Vault HMAC:"); - System.out.println("\t" + baseAddress + "digests/digest/hmac-1/text"); - System.out.println("\t" + baseAddress + "digests/digest/hmac-2/text/hmac"); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/package-info.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/package-info.java deleted file mode 100644 index 4496d133304..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of basic vault operations available in {@link io.helidon.security.Security}. - */ -package io.helidon.examples.security.vaults; diff --git a/examples/security/vaults/src/main/resources/application.yaml b/examples/security/vaults/src/main/resources/application.yaml deleted file mode 100644 index ec6dad51935..00000000000 --- a/examples/security/vaults/src/main/resources/application.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# -# All Hashicorp Vault configuration is commented out, as this PR only handles OCI -# This should be added in HCP Vault PR -# - -server: - port: 8080 - -app.token: "argb-urgx-harsps" - -vault: - token: "myroot" - address: "http://localhost:8200" - -security: - providers: - - config-vault: - master-password: "very much secret" - - vault-kv2: - address: "${vault.address}" - token: "${vault.token}" - - vault-transit: - address: "${vault.address}" - token: "${vault.token}" - - oci-vault: - # We need either the cryptographic endpoint (recommended), or management-endpoint configured - # Also ~/.oci/config must be correctly set up, otherwise all information is required here - # The crypto endpoint may be configured per digest/encryption, as we may use more than one - # vault in a single application - # vault.cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" - # vault.management-endpoint: "${oci.properties.management-endpoint}" - secrets: - - name: "username" - provider: "vault-kv2" - config: - path: "app/secret" - key: "username" - - name: "password" - provider: "oci-vault" - config: - ocid: "${oci.properties.secret-ocid}" - - name: "token" - provider: "config-vault" - config: - value: "${app.token}" - digest: - # Signatures and hmac - - name: "sig-2" - provider: "vault-transit" - config: - type: "signature" - key-name: "signature-key" - - name: "hmac-1" - provider: "vault-transit" - config: - type: "hmac" - key-name: "encryption-key" - - name: "sig-1" - provider: "oci-vault" - config: - cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" - key-ocid: "${oci.properties.vault-rsa-key-ocid}" - algorithm: "SHA_256_RSA_PKCS_PSS" - encryption: - # encryption and decryption - - name: "crypto-3" - provider: "vault-transit" - config: - key-name: "encryption-key" - - name: "crypto-1" - provider: "oci-vault" - config: - cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" - key-ocid: "${oci.properties.vault-key-ocid}" - - name: "crypto-2" - provider: "config-vault" diff --git a/examples/security/vaults/src/main/resources/logging.properties b/examples/security/vaults/src/main/resources/logging.properties deleted file mode 100644 index d0317654f47..00000000000 --- a/examples/security/vaults/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/security/webserver-digest-auth/README.md b/examples/security/webserver-digest-auth/README.md deleted file mode 100644 index 21791c2de28..00000000000 --- a/examples/security/webserver-digest-auth/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Web Server Integration and Digest Authentication - -This example demonstrates Integration of WebServer -based application with Security component and Digest authentication (from HttpAuthProvider). - -## Contents - -There are two examples with exactly the same behavior: -1. DigestExampleMain - shows how to programmatically secure application -2. DigestExampleConfigMain - shows how to secure application with configuration - 1. see src/main/resources/application.yaml for configuration - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-webserver-digest-auth.jar -``` - -Try the application: - -The application starts on a random port, the following assumes it is `56551` -```bash -curl http://localhost:56551/public -curl --digest -u "jill:password" http://localhost:56551/noRoles -curl --digest -u "john:password" http://localhost:56551/user -curl --digest -u "jack:password" http://localhost:56551/admin -curl -v --digest -u "john:password" http://localhost:56551/deny -curl --digest -u "jack:password" http://localhost:56551/noAuthn -``` diff --git a/examples/security/webserver-digest-auth/pom.xml b/examples/security/webserver-digest-auth/pom.xml deleted file mode 100644 index ff980c9223d..00000000000 --- a/examples/security/webserver-digest-auth/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-webserver-digest-auth - Helidon Security Examples Digest Authentication - - - This example demonstrates Integration of RX Web Server based application with Security component and Digest - authentication (from HttpAuthProvider). - - - - io.helidon.security.examples.webserver.digest.DigestExampleConfigMain - - - - - io.helidon.security.integration - helidon-security-integration-webserver - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.jersey - helidon-jersey-client - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderMain.java b/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderMain.java deleted file mode 100644 index 641201c0420..00000000000 --- a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderMain.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.digest; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.LogConfig; -import io.helidon.common.http.MediaType; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.security.providers.httpauth.HttpDigest; -import io.helidon.security.providers.httpauth.HttpDigestAuthProvider; -import io.helidon.security.providers.httpauth.SecureUserStore; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Example of HTTP digest authentication with WebServer fully configured programmatically. - */ -public final class DigestExampleBuilderMain { - // used from unit tests - private static WebServer server; - // simple approach to user storage - for real world, use data store... - private static Map users = new HashMap<>(); - - private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); - - static { - users.put("jack", new MyUser("jack", "password".toCharArray(), Set.of("user", "admin"))); - users.put("jill", new MyUser("jill", "password".toCharArray(), Set.of("user"))); - users.put("john", new MyUser("john", "password".toCharArray(), Set.of())); - } - - private DigestExampleBuilderMain() { - } - - /** - * Starts this example. Programmatical configuration. See standard output for instructions. - * - * @param args ignored - */ - public static void main(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - // build routing (same as done in application.conf) - Routing routing = Routing.builder() - .register(buildWebSecurity().securityDefaults(WebSecurity.authenticate())) - .get("/noRoles", WebSecurity.enforce()) - .get("/user[/{*}]", WebSecurity.rolesAllowed("user")) - .get("/admin", WebSecurity.rolesAllowed("admin")) - // audit is not enabled for GET methods by default - .get("/deny", WebSecurity.rolesAllowed("deny").audit()) - // roles allowed imply authn and authz - .any("/noAuthn", WebSecurity.rolesAllowed("admin") - .authenticationOptional() - .audit()) - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - }) - .build(); - - // start server (blocks until started) - server = DigestExampleUtil.startServer(routing); - } - - private static WebSecurity buildWebSecurity() { - Security security = Security.builder() - .addAuthenticationProvider( - HttpDigestAuthProvider.builder() - .realm("mic") - .digestServerSecret("aPassword".toCharArray()) - .userStore(buildUserStore()), - "digest-auth") - .build(); - return WebSecurity.create(security); - } - - private static SecureUserStore buildUserStore() { - return login -> Optional.ofNullable(users.get(login)); - } - - static WebServer getServer() { - return server; - } - - private static class MyUser implements SecureUserStore.User { - private String login; - private char[] password; - private Set roles; - - private MyUser(String login, char[] password, Set roles) { - this.login = login; - this.password = password; - this.roles = roles; - } - - private char[] password() { - return password; - } - - private static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars); - } - - @Override - public boolean isPasswordValid(char[] password) { - return Arrays.equals(password(), password); - } - - @Override - public Optional digestHa1(String realm, HttpDigest.Algorithm algorithm) { - if (algorithm != HttpDigest.Algorithm.MD5) { - throw new IllegalArgumentException("Unsupported algorithm " + algorithm); - } - String a1 = login + ":" + realm + ":" + new String(password()); - byte[] bytes = a1.getBytes(StandardCharsets.UTF_8); - MessageDigest digest; - try { - digest = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("MD5 algorithm should be supported", e); - } - return Optional.of(bytesToHex(digest.digest(bytes))); - } - - @Override - public Set roles() { - return roles; - } - - @Override - public String login() { - return login; - } - } -} diff --git a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigMain.java b/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigMain.java deleted file mode 100644 index 3e78391635d..00000000000 --- a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigMain.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.digest; - -import java.util.Optional; - -import io.helidon.common.LogConfig; -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.security.SecurityContext; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Example of HTTP digest authentication with RX Web Server fully configured in config file. - */ -public final class DigestExampleConfigMain { - // used from unit tests - private static WebServer server; - - private DigestExampleConfigMain() { - } - - /** - * Starts this example. Loads configuration from src/main/resources/application.conf. See standard output for instructions. - * - * @param args ignored - */ - public static void main(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - // load configuration - Config config = Config.create(); - - // build routing (security is loaded from config) - Routing routing = Routing.builder() - // helper method to load both security and web server security from configuration - .register(WebSecurity.create(config.get("security"))) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - }) - .build(); - - server = DigestExampleUtil.startServer(routing); - } - - static WebServer getServer() { - return server; - } -} diff --git a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleUtil.java b/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleUtil.java deleted file mode 100644 index dbefcf05c5e..00000000000 --- a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/DigestExampleUtil.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.digest; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Utility for this example. - */ -final class DigestExampleUtil { - private static final int START_TIMEOUT_SECONDS = 10; - - private DigestExampleUtil() { - } - - static WebServer startServer(Routing routing) { - WebServer server = WebServer.create(routing); - long t = System.nanoTime(); - - CountDownLatch cdl = new CountDownLatch(1); - - server.start().thenAccept(webServer -> { - long time = System.nanoTime() - t; - System.out.printf("Server started in %d ms ms%n", TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - System.out.printf("Started server on localhost:%d%n", webServer.port()); - System.out.println(); - System.out.println("Users:"); - System.out.println("Jack/password in roles: user, admin"); - System.out.println("Jill/password in roles: user"); - System.out.println("John/password in no roles"); - System.out.println(); - System.out.println("***********************"); - System.out.println("** Endpoints: **"); - System.out.println("***********************"); - System.out.println("No authentication:"); - System.out.printf(" http://localhost:%1$d/public%n", webServer.port()); - System.out.println("No roles required, authenticated:"); - System.out.printf(" http://localhost:%1$d/noRoles%n", webServer.port()); - System.out.println("User role required:"); - System.out.printf(" http://localhost:%1$d/user%n", webServer.port()); - System.out.println("Admin role required:"); - System.out.printf(" http://localhost:%1$d/admin%n", webServer.port()); - System.out.println("Always forbidden (uses role nobody is in), audited:"); - System.out.printf(" http://localhost:%1$d/deny%n", webServer.port()); - System.out.println( - "Admin role required, authenticated, authentication optional, audited (always forbidden - challenge is not " - + "returned as authentication is optional):"); - System.out.printf(" http://localhost:%1$d/noAuthn%n", webServer.port()); - System.out.println(); - cdl.countDown(); - }); - - try { - cdl.await(START_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException("Failed to start server within defined timeout: " + START_TIMEOUT_SECONDS + " seconds", e); - } - return server; - } -} diff --git a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/package-info.java b/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/package-info.java deleted file mode 100644 index 775d49bbfee..00000000000 --- a/examples/security/webserver-digest-auth/src/main/java/io/helidon/security/examples/webserver/digest/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of Digest authentication on top of RX web server. - * - * @see io.helidon.security.examples.webserver.digest.DigestExampleConfigMain Configuration based example - * @see io.helidon.security.examples.webserver.digest.DigestExampleBuilderMain Programmatic example - */ -package io.helidon.security.examples.webserver.digest; diff --git a/examples/security/webserver-digest-auth/src/main/resources/application.yaml b/examples/security/webserver-digest-auth/src/main/resources/application.yaml deleted file mode 100644 index 4bea9c12abd..00000000000 --- a/examples/security/webserver-digest-auth/src/main/resources/application.yaml +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (c) 2016, 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -security: - config: - # Configuration of secured config (encryption of passwords in property files) - # Set to true for production - if set to true, clear text passwords will cause failure - require-encryption: false - providers: - - http-digest-auth: - realm: "mic" - server-secret: "aPassword" - users: - - login: "jack" - password: "${CLEAR=password}" - roles: ["user", "admin"] - - login: "jill" - password: "${CLEAR=password}" - roles: ["user"] - - login: "john" - password: "${CLEAR=password}" - roles: [] - web-server: - # Configuration of integration with web server - defaults: - authenticate: true - paths: - - path: "/noRoles" - methods: ["get"] - - path: "/user[/{*}]" - methods: ["get"] - roles-allowed: ["user"] - - path: "/admin" - methods: ["get"] - roles-allowed: ["admin"] - - path: "/deny" - methods: ["get"] - roles-allowed: ["deny"] - audit: true - - path: "/noAuthn" - roles-allowed: ["admin"] - authentication-optional: true - audit: true diff --git a/examples/security/webserver-digest-auth/src/main/resources/logging.properties b/examples/security/webserver-digest-auth/src/main/resources/logging.properties deleted file mode 100644 index 809e33bb018..00000000000 --- a/examples/security/webserver-digest-auth/src/main/resources/logging.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n -#All log level details -.level=WARNING -io.helidon.webserver.level=FINEST -io.helidon.security.level=FINEST -AUDIT.level=FINEST diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderTest.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderTest.java deleted file mode 100644 index c9791cd17ae..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleBuilderTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.digest; - -import java.io.IOException; - -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Unit test for {@link DigestExampleBuilderMain}. - */ -public class DigestExampleBuilderTest extends DigestExampleTest { - - private static WebServer server; - - @BeforeAll - public static void startServer() throws IOException { - // start the test - DigestExampleBuilderMain.main(new String[0]); - server = DigestExampleBuilderMain.getServer(); - } - - @AfterAll - public static void stopServer() throws InterruptedException { - stopServer(server); - } - - @Override - String getServerBase() { - return "http://localhost:" + server.port(); - } -} diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigTest.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigTest.java deleted file mode 100644 index ff81b462fd4..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleConfigTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.digest; - -import java.io.IOException; - -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** - * Unit test for {@link DigestExampleConfigMain}. - */ -public class DigestExampleConfigTest extends DigestExampleTest { - - private static WebServer server; - - @BeforeAll - public static void startServer() throws IOException { - // start the test - DigestExampleConfigMain.main(new String[0]); - server = DigestExampleConfigMain.getServer(); - } - - @AfterAll - public static void stopServer() throws InterruptedException { - stopServer(server); - } - - @Override - String getServerBase() { - return "http://localhost:" + server.port(); - } -} diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleTest.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleTest.java deleted file mode 100644 index c2cb7188867..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/security/examples/webserver/digest/DigestExampleTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.webserver.digest; - -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.helidon.webserver.WebServer; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.Response; -import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.HTTP_AUTHENTICATION_PASSWORD; -import static org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.HTTP_AUTHENTICATION_USERNAME; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Abstract class with tests for this example (used by programmatic and config based tests). - */ -public abstract class DigestExampleTest { - private static Client client; - private static Client authFeatureClient; - - @BeforeAll - public static void classInit() { - client = ClientBuilder.newClient(); - authFeatureClient = ClientBuilder.newClient() - .register(HttpAuthenticationFeature.digest()); - } - - @AfterAll - public static void classDestroy() { - client.close(); - authFeatureClient.close(); - } - - static void stopServer(WebServer server) throws InterruptedException { - CountDownLatch cdl = new CountDownLatch(1); - long t = System.nanoTime(); - server.shutdown().thenAccept(webServer -> { - long time = System.nanoTime() - t; - System.out.println("Server shutdown in " + TimeUnit.NANOSECONDS.toMillis(time) + " ms"); - cdl.countDown(); - }); - - if (!cdl.await(5, TimeUnit.SECONDS)) { - throw new IllegalStateException("Failed to shutdown server within 5 seconds"); - } - } - - abstract String getServerBase(); - - //now for the tests - @Test - public void testPublic() { - //Must be accessible without authentication - try (Response response = client.target(getServerBase() + "/public").request().get()) { - assertThat(response.getStatus(), is(200)); - String entity = response.readEntity(String.class); - assertThat(entity, containsString("")); - } - } - - @Test - public void testNoRoles() { - String url = getServerBase() + "/noRoles"; - - testNotAuthorized(client, url); - - //Must be accessible with authentication - to everybody - testProtected(url, "jack", "password", Set.of("admin", "user"), Set.of()); - testProtected(url, "jill", "password", Set.of("user"), Set.of("admin")); - testProtected(url, "john", "password", Set.of(), Set.of("admin", "user")); - } - - @Test - public void testUserRole() { - String url = getServerBase() + "/user"; - - testNotAuthorized(client, url); - - //Jack and Jill allowed (user role) - testProtected(url, "jack", "password", Set.of("admin", "user"), Set.of()); - testProtected(url, "jill", "password", Set.of("user"), Set.of("admin")); - testProtectedDenied(url, "john", "password"); - } - - @Test - public void testAdminRole() { - String url = getServerBase() + "/admin"; - - testNotAuthorized(client, url); - - //Only jack is allowed - admin role... - testProtected(url, "jack", "password", Set.of("admin", "user"), Set.of()); - testProtectedDenied(url, "jill", "password"); - testProtectedDenied(url, "john", "password"); - } - - @Test - public void testDenyRole() { - String url = getServerBase() + "/deny"; - - testNotAuthorized(client, url); - - // nobody has the correct role - testProtectedDenied(url, "jack", "password"); - testProtectedDenied(url, "jill", "password"); - testProtectedDenied(url, "john", "password"); - } - - @Test - public void getNoAuthn() { - String url = getServerBase() + "/noAuthn"; - //Must NOT be accessible without authentication - try (Response response = client.target(url).request().get()) { - // authentication is optional, so we are not challenged, only forbidden, as the role can never be there... - assertThat(response.getStatus(), is(403)); - - // doesn't matter, we are never challenged - testProtectedDenied(url, "jack", "password"); - testProtectedDenied(url, "jill", "password"); - testProtectedDenied(url, "john", "password"); - } - } - - private void testNotAuthorized(Client client, String uri) { - //Must NOT be accessible without authentication - try (Response response = client.target(uri).request().get()) { - assertThat(response.getStatus(), is(401)); - String header = response.getHeaderString("WWW-Authenticate"); - assertThat(header, notNullValue()); - assertThat(header.toLowerCase(), containsString("digest")); - assertThat(header, containsString("mic")); - } - } - - private Response callProtected(String uri, String username, String password) { - // here we call the endpoint - return authFeatureClient.target(uri) - .request() - .property(HTTP_AUTHENTICATION_USERNAME, username) - .property(HTTP_AUTHENTICATION_PASSWORD, password) - .get(); - } - - private void testProtectedDenied(String uri, - String username, - String password) { - - try (Response response = callProtected(uri, username, password)) { - assertThat(response.getStatus(), is(403)); - } - } - - private void testProtected(String uri, - String username, - String password, - Set expectedRoles, - Set invalidRoles) { - - try (Response response = callProtected(uri, username, password)) { - String entity = response.readEntity(String.class); - - assertThat(response.getStatus(), is(200)); - - // check login - assertThat(entity, containsString("id='" + username + "'")); - // check roles - expectedRoles.forEach(role -> assertThat(entity, containsString(":" + role))); - invalidRoles.forEach(role -> assertThat(entity, not(containsString(":" + role)))); - } - } -} diff --git a/examples/security/webserver-signatures/README.md b/examples/security/webserver-signatures/README.md deleted file mode 100644 index a1a1bc7b663..00000000000 --- a/examples/security/webserver-signatures/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Web Server Integration and HTTP Signatures - -This example demonstrates Integration of WebServer -based application with Security component and HTTP Signatures. - -## Contents - -There are two examples with exactly the same behavior -1. builder - shows how to programmatically secure application -2. config - shows how to secure application with configuration - 1. see `src/main/resources/service1.yaml` and `src/main/resources/service2.conf` for configuration -3. Each consists of two services - 1. "public" service protected by basic authentication (for simplicity) - 2. "internal" service protected by a combination of basic authentication (for user propagation) and http signature - (for service authentication) - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-security-webserver-signatures.jar -``` - -Try the endpoints: -```bash -curl -u "jack:password" http://localhost:8080/service1 -curl -u "jill:password" http://localhost:8080/service1-rsa -curl -v -u "john:password" http://localhost:8080/service1 -``` diff --git a/examples/security/webserver-signatures/pom.xml b/examples/security/webserver-signatures/pom.xml deleted file mode 100644 index af3a34de221..00000000000 --- a/examples/security/webserver-signatures/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-webserver-signatures - Helidon Security Examples HTTP Signatures - - - This example demonstrates Integration of RX Web Server based application with Security component and HTTP - Signatures - - - - io.helidon.security.examples.signatures.SignatureExampleConfigMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.security.integration - helidon-security-integration-webserver - - - io.helidon.security.integration - helidon-security-integration-jersey-client - - - io.helidon.bundles - helidon-bundles-security - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.config - helidon-config-hocon - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-security - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleBuilderMain.java b/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleBuilderMain.java deleted file mode 100644 index 6c424190482..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleBuilderMain.java +++ /dev/null @@ -1,242 +0,0 @@ - -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package io.helidon.security.examples.signatures; - -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.common.configurable.Resource; -import io.helidon.common.http.MediaType; -import io.helidon.common.pki.KeyConfig; -import io.helidon.security.CompositeProviderFlag; -import io.helidon.security.CompositeProviderSelectionPolicy; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.security.providers.common.OutboundConfig; -import io.helidon.security.providers.common.OutboundTarget; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.security.providers.httpauth.SecureUserStore; -import io.helidon.security.providers.httpsign.HttpSignProvider; -import io.helidon.security.providers.httpsign.InboundClientDefinition; -import io.helidon.security.providers.httpsign.OutboundTargetDefinition; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Example of authentication of service with http signatures, using configuration file as much as possible. - */ -public class SignatureExampleBuilderMain { - private static final Map USERS = new HashMap<>(); - // used from unit tests - private static WebServer service1Server; - private static WebServer service2Server; - - static { - addUser("jack", "password", List.of("user", "admin")); - addUser("jill", "password", List.of("user")); - addUser("john", "password", List.of()); - } - - private SignatureExampleBuilderMain() { - } - - public static WebServer getService1Server() { - return service1Server; - } - - public static WebServer getService2Server() { - return service2Server; - } - - private static void addUser(String user, String password, List roles) { - USERS.put(user, new SecureUserStore.User() { - @Override - public String login() { - return user; - } - - char[] password() { - return password.toCharArray(); - } - - @Override - public boolean isPasswordValid(char[] password) { - return Arrays.equals(password(), password); - } - - @Override - public Collection roles() { - return roles; - } - }); - } - - /** - * Starts this example. - * - * @param args ignored - */ - public static void main(String[] args) { - // to allow us to set host header explicitly - System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); - - // start service 2 first, as it is required by service 1 - service2Server = SignatureExampleUtil.startServer(routing2(), 9080); - service1Server = SignatureExampleUtil.startServer(routing1(), 8080); - - System.out.println("Signature example: from builder"); - System.out.println(); - System.out.println("Users:"); - System.out.println("jack/password in roles: user, admin"); - System.out.println("jill/password in roles: user"); - System.out.println("john/password in no roles"); - System.out.println(); - System.out.println("***********************"); - System.out.println("** Endpoints: **"); - System.out.println("***********************"); - System.out.println("Basic authentication, user role required, will use symmetric signatures for outbound:"); - System.out.printf(" http://localhost:%1$d/service1%n", service1Server.port()); - System.out.println("Basic authentication, user role required, will use asymmetric signatures for outbound:"); - System.out.printf(" http://localhost:%1$d/service1-rsa%n", service2Server.port()); - System.out.println(); - } - - private static Routing routing2() { - - // build routing (security is loaded from config) - return Routing.builder() - // helper method to load both security and web server security from configuration - .register(WebSecurity.create(security2()).securityDefaults(WebSecurity.authenticate())) - .get("/service2", WebSecurity.rolesAllowed("user")) - .get("/service2-rsa", WebSecurity.rolesAllowed("user")) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Response from service2, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null") + ", service: " + securityContext - .flatMap(SecurityContext::service) - .map(Subject::toString)); - }) - .build(); - } - - private static Routing routing1() { - // build routing (security is loaded from config) - return Routing.builder() - .register(WebSecurity.create(security1()).securityDefaults(WebSecurity.authenticate())) - .get("/service1", - WebSecurity.rolesAllowed("user"), - (req, res) -> SignatureExampleUtil.processService1Request(req, res, "/service2", service2Server.port())) - .get("/service1-rsa", - WebSecurity.rolesAllowed("user"), - (req, res) -> SignatureExampleUtil.processService1Request(req, res, "/service2-rsa", service2Server.port())) - .build(); - } - - private static Security security2() { - return Security.builder() - .providerSelectionPolicy(CompositeProviderSelectionPolicy.builder() - .addAuthenticationProvider("http-signatures", CompositeProviderFlag.OPTIONAL) - .addAuthenticationProvider("basic-auth") - .build()) - .addProvider(HttpBasicAuthProvider.builder() - .realm("mic") - .userStore(users()), - "basic-auth") - .addProvider(HttpSignProvider.builder() - .addInbound(InboundClientDefinition.builder("service1-hmac") - .principalName("Service1 - HMAC signature") - .hmacSecret("somePasswordForHmacShouldBeEncrypted") - .build()) - .addInbound(InboundClientDefinition.builder("service1-rsa") - .principalName("Service1 - RSA signature") - .publicKeyConfig(KeyConfig.keystoreBuilder() - .keystore(Resource.create(Paths.get( - "src/main/resources/keystore.p12"))) - .keystorePassphrase("password".toCharArray()) - .certAlias("service_cert") - .build()) - .build()) - .build(), - "http-signatures") - .build(); - } - - private static Security security1() { - return Security.builder() - .providerSelectionPolicy(CompositeProviderSelectionPolicy.builder() - .addOutboundProvider("basic-auth") - .addOutboundProvider("http-signatures") - .build()) - .addProvider(HttpBasicAuthProvider.builder() - .realm("mic") - .userStore(users()) - .addOutboundTarget(OutboundTarget.builder("propagate-all").build()), - "basic-auth") - .addProvider(HttpSignProvider.builder() - .outbound(OutboundConfig.builder() - .addTarget(hmacTarget()) - .addTarget(rsaTarget()) - .build()), - "http-signatures") - .build(); - } - - private static OutboundTarget rsaTarget() { - return OutboundTarget.builder("service2-rsa") - .addHost("localhost") - .addPath("/service2-rsa.*") - .customObject(OutboundTargetDefinition.class, - OutboundTargetDefinition.builder("service1-rsa") - .privateKeyConfig(KeyConfig.keystoreBuilder() - .keystore(Resource.create(Paths.get( - "src/main/resources/keystore.p12"))) - .keystorePassphrase("password".toCharArray()) - .keyAlias("myPrivateKey") - .build()) - .build()) - .build(); - } - - private static OutboundTarget hmacTarget() { - return OutboundTarget.builder("service2") - .addHost("localhost") - .addPath("/service2") - .customObject( - OutboundTargetDefinition.class, - OutboundTargetDefinition.builder("service1-hmac") - .hmacSecret("somePasswordForHmacShouldBeEncrypted") - .build()) - .build(); - } - - private static SecureUserStore users() { - return login -> Optional.ofNullable(USERS.get(login)); - } -} diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleConfigMain.java b/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleConfigMain.java deleted file mode 100644 index c25b749c631..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleConfigMain.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.signatures; - -import java.util.Optional; - -import io.helidon.common.http.MediaType; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Example of authentication of service with http signatures, using configuration file as much as possible. - */ -public class SignatureExampleConfigMain { - - // used from unit tests - private static WebServer service1Server; - private static WebServer service2Server; - - private SignatureExampleConfigMain() { - } - - /** - * Starts this example. - * - * @param args ignored - */ - public static void main(String[] args) { - // to allow us to set host header explicitly - System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); - - // start service 2 first, as it is required by service 1 - service2Server = SignatureExampleUtil.startServer(routing2(), 9080); - service1Server = SignatureExampleUtil.startServer(routing1(), 8080); - - System.out.println("Signature example: from configuration"); - System.out.println(); - System.out.println("Users:"); - System.out.println("jack/password in roles: user, admin"); - System.out.println("jill/password in roles: user"); - System.out.println("john/password in no roles"); - System.out.println(); - System.out.println("***********************"); - System.out.println("** Endpoints: **"); - System.out.println("***********************"); - System.out.println("Basic authentication, user role required, will use symmetric signatures for outbound:"); - System.out.printf(" http://localhost:%1$d/service1%n", service1Server.port()); - System.out.println("Basic authentication, user role required, will use asymmetric signatures for outbound:"); - System.out.printf(" http://localhost:%1$d/service1-rsa%n", service1Server.port()); - System.out.println(); - } - - private static Routing routing2() { - Config config = config("service2.yaml"); - // build routing (security is loaded from config) - return Routing.builder() - // helper method to load both security and web server security from configuration - .register(WebSecurity.create(config.get("security"))) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Response from service2, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null") + ", service: " + securityContext - .flatMap(SecurityContext::service) - .map(Subject::toString)); - }) - .build(); - } - - private static Routing routing1() { - Config config = config("service1.yaml"); - - // build routing (security is loaded from config) - return Routing.builder() - // helper method to load both security and web server security from configuration - .register(WebSecurity.create(config.get("security"))) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/service1", (req, res) -> { - SignatureExampleUtil.processService1Request(req, res, "/service2", service2Server.port()); - }) - .get("/service1-rsa", (req, res) -> { - SignatureExampleUtil.processService1Request(req, res, "/service2-rsa", service2Server.port()); - }) - .build(); - } - - private static Config config(String confFile) { - // load configuration - return Config.builder() - .sources(ConfigSources.classpath(confFile)) - .build(); - } - - static WebServer getService1Server() { - return service1Server; - } - - static WebServer getService2Server() { - return service2Server; - } -} diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleUtil.java b/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleUtil.java deleted file mode 100644 index 18b5d68ca05..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/SignatureExampleUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.security.examples.signatures; - -import java.util.Optional; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.security.SecurityContext; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.WebServer; - -/** - * Common code for both examples (builder and config based). - */ -final class SignatureExampleUtil { - private static final WebClient CLIENT = WebClient.builder() - .addService(WebClientSecurity.create()) - .build(); - - private static final int START_TIMEOUT_SECONDS = 10; - - private SignatureExampleUtil() { - } - - /** - * Start a web server. - * - * @param routing routing to configre - * @return started web server instance - */ - public static WebServer startServer(Routing routing, int port) { - WebServer server = WebServer.builder(routing) - .port(port) - .build(); - long t = System.nanoTime(); - - CountDownLatch cdl = new CountDownLatch(1); - - server.start().thenAccept(webServer -> { - long time = System.nanoTime() - t; - - System.out.printf("Server started in %d ms ms%n", TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - System.out.printf("Started server on localhost:%d%n", webServer.port()); - System.out.println(); - cdl.countDown(); - }).exceptionally(throwable -> { - throw new RuntimeException("Failed to start server", throwable); - }); - - try { - cdl.await(START_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException("Failed to start server within defined timeout: " + START_TIMEOUT_SECONDS + " seconds"); - } - return server; - } - - static void processService1Request(ServerRequest req, ServerResponse res, String path, int svc2port) { - Optional securityContext = req.context().get(SecurityContext.class); - - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - - securityContext.ifPresentOrElse(context -> { - CLIENT.get() - .uri("http://localhost:" + svc2port + path) - .request() - .thenAccept(it -> { - if (it.status() == Http.Status.OK_200) { - it.content().as(String.class) - .thenAccept(res::send) - .exceptionally(throwable -> { - res.send("Getting server response failed!"); - return null; - }); - } else { - res.send("Request failed, status: " + it.status()); - } - }); - - }, () -> res.send("Security context is null")); - } -} diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/package-info.java b/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/package-info.java deleted file mode 100644 index c8338448c4e..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/security/examples/signatures/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of HTTP Signatures (both inbound and outbound). - * Based on RFC draft: https://tools.ietf - * .org/html/draft-cavage-http-signatures-03 - */ -package io.helidon.security.examples.signatures; diff --git a/examples/security/webserver-signatures/src/main/resources/keystore.p12 b/examples/security/webserver-signatures/src/main/resources/keystore.p12 deleted file mode 100644 index ff2c52d6694ae5c23a1b15d971935a9fa33ba1d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2700 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 { - long time = System.nanoTime() - t; - System.out.println("Server shutdown in " + TimeUnit.NANOSECONDS.toMillis(time) + " ms"); - cdl.countDown(); - }); - - if (!cdl.await(5, TimeUnit.SECONDS)) { - throw new IllegalStateException("Failed to shutdown server within 5 seconds"); - } - } - - abstract int getService1Port(); - - abstract int getService2Port(); - - @Test - public void testService1Hmac() { - testProtected("http://localhost:" + getService1Port() + "/service1", - "jack", - "password", - Set.of("user", "admin"), - Set.of(), - "Service1 - HMAC signature"); - } - - @Test - public void testService1Rsa() { - testProtected("http://localhost:" + getService1Port() + "/service1-rsa", - "jack", - "password", - Set.of("user", "admin"), - Set.of(), - "Service1 - RSA signature"); - } - - - private void testProtected(String uri, - String username, - String password, - Set expectedRoles, - Set invalidRoles, - String service) { - client.get() - .uri(uri) - .property(PROPERTY_OUTBOUND_ID, username) - .property(PROPERTY_OUTBOUND_SECRET, password) - .request(String.class) - .thenAccept(it -> { - // check login - assertThat(it, containsString("id='" + username + "'")); - // check roles - expectedRoles.forEach(role -> assertThat(it, containsString(":" + role))); - invalidRoles.forEach(role -> assertThat(it, not(containsString(":" + role)))); - - assertThat(it, containsString("id='" + service + "'")); - }) - .await(); - } -} diff --git a/examples/todo-app/README.md b/examples/todo-app/README.md deleted file mode 100644 index 43294d76d03..00000000000 --- a/examples/todo-app/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# TODO Demo Application - -This application implements todomvc[http://todomvc.com] with two microservices -implemented with Helidon MP and Helidon SE. - -## Build - -```bash -mvn clean package -docker build -t helidon-examples-todo-cassandra cassandra -``` - -## Run - -```bash -docker run -d -p 9042:9042 --name helidon-examples-todo-cassandra helidon-examples-todo-cassandra -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -java -jar backend/target/helidon-examples-todo-backend.jar & -java -jar frontend/target/helidon-examples-todo-frontend.jar & -``` - -- Open http://localhost:8080 in your browser -- Login with a Google account -- Add some TODO entries -- Check-out the traces at http://localhost:9411 - -### HTTP proxy - -If you want to run behind an HTTP proxy: - -```bash -export security_providers_0_google_dash_login_proxy_dash_host=proxy.acme.com -export security_providers_0_google_dash_login_proxy_dash_port=80 -``` - -## Stop - -```bash -kill %1 %2 -docker rm -f zipkin helidon-examples-todo-cassandra -``` diff --git a/examples/todo-app/backend/pom.xml b/examples/todo-app/backend/pom.xml deleted file mode 100644 index ee19db55f03..00000000000 --- a/examples/todo-app/backend/pom.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 3.2.7-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.todos - helidon-examples-todo-backend - Helidon Examples TODO Demo Backend - - - Back-end part of the application uses Helidon MP - - - - io.helidon.demo.todos.backend.Main - 3.10.2 - 4.3.1.0 - 4.9.0 - 4.9.0 - 3.0.2 - 1.32 - - - - - - com.datastax.cassandra - cassandra-driver-core - ${version.lib.cassandra} - - - io.dropwizard.metrics - metrics-core - - - - - org.yaml - snakeyaml - ${version.lib.snakeyaml.override} - - - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile - helidon-microprofile-security - - - io.helidon.security.providers - helidon-security-providers-google-login - - - io.helidon.security.providers - helidon-security-providers-http-sign - - - io.helidon.security.providers - helidon-security-providers-abac - - - io.helidon.microprofile.tracing - helidon-microprofile-tracing - - - io.helidon.tracing - helidon-tracing-zipkin - - - com.fasterxml.jackson.core - jackson-core - - - com.datastax.cassandra - cassandra-driver-core - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.microprofile.tests - helidon-microprofile-tests-junit5 - test - - - org.cassandraunit - cassandra-unit - ${version.cassandra.unit} - test - - - com.datastax.oss - java-driver-core - ${version.datastax.driver.core} - test - - - com.datastax.oss - java-driver-query-builder - ${version.datastax.driver.query.builder} - test - - - com.codahale.metrics - metrics-core - ${version.codahale.metrics.core} - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.jboss.jandex - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/DbService.java b/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/DbService.java deleted file mode 100644 index 4de507a1630..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/DbService.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2017, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.backend; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.security.SecurityException; - -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.Session; -import io.opentracing.Span; -import io.opentracing.SpanContext; -import io.opentracing.tag.Tags; -import io.opentracing.util.GlobalTracer; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -/** - * A service showing to access a no-SQL database. - */ -@ApplicationScoped -public class DbService { - - private static final String LIST_QUERY = "select * from backend where user = ? ALLOW FILTERING"; - private static final String GET_QUERY = "select * from backend where id = ?"; - private static final String INSERT_QUERY = "insert into backend (id, user, message, completed, created)" - + " values (?, ?, ?, ?, ?)"; - private static final String UPDATE_QUERY = "update backend set message = ?, completed = ? where id = ? if user = ?"; - private static final String DELETE_QUERY = "delete from backend where id = ?"; - - private final Session session; - private final PreparedStatement listStatement; - private final PreparedStatement getStatement; - private final PreparedStatement insertStatement; - private final PreparedStatement updateStatement; - private final PreparedStatement deleteStatement; - - /** - * Create a new {@code DbService} instance. - * @param config the configuration root - */ - @Inject - public DbService(Config config) { - Cluster.Builder clusterBuilder = Cluster.builder() - .withoutMetrics(); - - Config cConfig = config.get("cassandra"); - cConfig.get("servers").asList(Config.class).stream() - .flatMap(Collection::stream) - .map(server -> server.get("host").asString().get()) - .forEach(clusterBuilder::addContactPoints); - cConfig.get("port").asInt().ifPresent(clusterBuilder::withPort); - - Cluster cluster = clusterBuilder.build(); - session = cluster.connect("backend"); - - listStatement = session.prepare(LIST_QUERY); - getStatement = session.prepare(GET_QUERY); - insertStatement = session.prepare(INSERT_QUERY); - updateStatement = session.prepare(UPDATE_QUERY); - deleteStatement = session.prepare(DELETE_QUERY); - } - - /** - * Invoke the given supplier and wrap it around with a tracing - * {@code Span}. - * @param the supplier return type - * @param tracingSpan the parent span to use - * @param operation the name of the operation - * @param supplier the supplier to invoke - * @return the object returned by the supplier - */ - private static T execute(SpanContext tracingSpan, String operation, Supplier supplier) { - Span span = startSpan(tracingSpan, operation); - - try { - return supplier.get(); - } catch (Exception e) { - Tags.ERROR.set(span, true); - span.log(Map.of("event", "error", "error.object", e)); - throw e; - } finally { - span.finish(); - } - } - - /** - * Utility method to create and start a child span of the given span. - * @param span the parent span - * @param operation the name for the new span - * @return the created span - */ - private static Span startSpan(SpanContext span, String operation) { - return GlobalTracer.get().buildSpan(operation).asChildOf(span).start(); - } - - /** - * Retrieve the TODOs entries from the database. - * @param tracingSpan the tracing span to use - * @param userId the database user id - * @return retrieved entries as {@code Iterable} - */ - Iterable list(SpanContext tracingSpan, String userId) { - return execute(tracingSpan, "cassandra::list", () -> { - BoundStatement bs = listStatement.bind(userId); - ResultSet rs = session.execute(bs); - - List result = new ArrayList<>(); - for (Row r : rs) { - result.add(Todo.fromDb(r)); - } - - return result; - }); - } - - /** - * Get the entry identified by the given ID from the database. - * @param tracingSpan the tracing span to use - * @param id the ID identifying the entry to retrieve - * @param userId the database user id - * @return retrieved entry as {@code Optional} - */ - Optional get(SpanContext tracingSpan, String id, String userId) { - return execute(tracingSpan, "cassandra::get", () -> getNoContext(id, userId)); - } - - /** - * Get the entry identified by the given ID from the database, fails if the - * entry is not associated with the given {@code userId}. - * @param id the ID identifying the entry to retrieve - * @param userId the database user id - * @return retrieved entry as {@code Optional} - */ - private Optional getNoContext(String id, String userId) { - BoundStatement bs = getStatement.bind(id); - ResultSet rs = session.execute(bs); - Row one = rs.one(); - if (null == one) { - return Optional.empty(); - } - Todo result = Todo.fromDb(one); - if (userId.equals(result.getUserId())) { - return Optional.of(result); - } - throw new SecurityException(String.format( - "User %s attempted to read record %s of another user", - userId, id)); - } - - /** - * Update the given entry in the database. - * @param tracingSpan the tracing span to use - * @param entry the entry to update - * @return {@code Optional} of updated entry if the update was successful, - * otherwise an empty {@code Optional} - */ - Optional update(SpanContext tracingSpan, Todo entry) { - return execute(tracingSpan, "cassandra::update", () -> { - //update backend set message = ? - // , completed = ? where id = ? if user = ? - BoundStatement bs = updateStatement.bind( - entry.getTitle(), - entry.getCompleted(), - entry.getId(), - entry.getUserId()); - ResultSet execute = session.execute(bs); - - if (execute.wasApplied()) { - return Optional.of(entry); - } else { - return Optional.empty(); - } - }); - } - - /** - * Delete the entry identified by the given ID in from the database. - * @param tracingSpan the tracing span to use - * @param id the ID identifying the entry to delete - * @param userId the database user id - * @return the deleted entry as {@code Optional} - */ - Optional delete(SpanContext tracingSpan, String id, String userId) { - return execute(tracingSpan, "cassandra::delete", - () -> getNoContext(id, userId) - .map(todo -> { - BoundStatement bs = deleteStatement.bind(id); - ResultSet rs = session.execute(bs); - if (!rs.wasApplied()) { - throw new RuntimeException("Failed to delete todo: " - + todo); - } - return todo; - })); - } - - /** - * Insert a new entry in the database. - * @param tracingSpan the tracing span to use - * @param entry the entry to insert - */ - void insert(SpanContext tracingSpan, Todo entry) { - execute(tracingSpan, "cassandra::insert", () -> { - BoundStatement bs = insertStatement - .bind(entry.getId(), - entry.getUserId(), - entry.getTitle(), - entry.getCompleted(), - new Date(entry.getCreated())); - - ResultSet execute = session.execute(bs); - if (!execute.wasApplied()) { - throw new RuntimeException("Failed to insert todo: " + entry); - } - return null; - }); - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/JaxRsBackendResource.java b/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/JaxRsBackendResource.java deleted file mode 100644 index 4d74877d840..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/JaxRsBackendResource.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2017, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.backend; - -import java.util.Collections; -import java.util.UUID; - -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.annotations.Authenticated; -import io.helidon.security.annotations.Authorized; - -import io.opentracing.Tracer; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.opentracing.Traced; - -/** - * The TODO backend REST service. - */ -@Path("/api/backend") -@Authenticated -@Authorized -@ApplicationScoped -public class JaxRsBackendResource { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private final DbService backendService; - private final Tracer tracer; - - /** - * Create new {@code JaxRsBackendResource} instance. - * @param dbs the database service facade to use - * @param tracer tracer to use - */ - @Inject - public JaxRsBackendResource(DbService dbs, Tracer tracer) { - this.backendService = dbs; - this.tracer = tracer; - } - - /** - * Retrieve all TODO entries. - * - * @param context security context to map the user - * @return the response with the retrieved entries as entity - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - @Traced(operationName = "jaxrs:list") - public Response list(@Context SecurityContext context) { - JsonArrayBuilder builder = JSON.createArrayBuilder(); - backendService.list(tracer.activeSpan().context(), getUserId(context)) - .forEach(data -> builder.add(data.forRest())); - return Response.ok(builder.build()).build(); - } - - /** - * Get the TODO entry identified by the given ID. - * @param id the ID of the entry to retrieve - * @param context security context to map the user - * @return the response with the retrieved entry as entity - */ - @GET - @Path("/{id}") - @Produces(MediaType.APPLICATION_JSON) - public Response get(@PathParam("id") String id, @Context SecurityContext context) { - - return backendService - .get(tracer.activeSpan().context(), id, getUserId(context)) - .map(Todo::forRest) - .map(Response::ok) - .orElse(Response.status(Response.Status.NOT_FOUND)) - .build(); - } - - /** - * Delete the TODO entry identified by the given ID. - * @param id the id of the entry to delete - * @param context security context to map the user - * @return the response with the deleted entry as entity - */ - @DELETE - @Path("/{id}") - @Produces(MediaType.APPLICATION_JSON) - public Response delete(@PathParam("id") String id, @Context SecurityContext context) { - - return backendService - .delete(tracer.activeSpan().context(), id, getUserId(context)) - .map(Todo::forRest) - .map(Response::ok) - .orElse(Response.status(Response.Status.NOT_FOUND)) - .build(); - } - - /** - * Create a new TODO entry. - * @param jsonObject the value of the new entry - * @param context security context to map the user - * @return the response ({@code 200} status if successful - */ - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response createIt(JsonObject jsonObject, @Context SecurityContext context) { - - String newId = UUID.randomUUID().toString(); - String userId = getUserId(context); - Todo newBackend = Todo.newTodoFromRest(jsonObject, userId, newId); - - backendService.insert(tracer.activeSpan().context(), newBackend); - - return Response.ok(newBackend.forRest()).build(); - } - - /** - * Update the TODO entry identified by the given ID. - * @param id the ID of the entry to update - * @param jsonObject the updated value of the entry - * @param context security context to map the user - * @return the response with the updated entry as entity - */ - @PUT - @Path("/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response update(@PathParam("id") String id, JsonObject jsonObject, @Context SecurityContext context) { - return backendService - .update(tracer.activeSpan().context(), Todo.fromRest(jsonObject, getUserId(context), id)) - .map(Todo::forRest) - .map(Response::ok) - .orElse(Response.status(Response.Status.NOT_FOUND)) - .build(); - } - - /** - * Get the user id from the security context. - * @param context the security context - * @return user id found in the context or {@code } otherwise - */ - private String getUserId(SecurityContext context) { - return context.user() - .map(Subject::principal) - .map(Principal::id) - .orElse(""); - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Main.java b/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Main.java deleted file mode 100644 index db29ad577ce..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Main.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2017, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.backend; - -import java.util.List; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.microprofile.server.Server; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.environmentVariables; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class to start the service. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments - */ - public static void main(final String[] args) { - - // load logging configuration - LogConfig.configureRuntime(); - - Config config = buildConfig(); - - // as we need to use custom filter - // we need to build Server with custom config - Server server = Server.builder() - .config(config) - .build(); - - server.start(); - } - - /** - * Load the configuration from all sources. - * @return the configuration root - */ - static Config buildConfig() { - return Config.builder() - .sources(List.of( - environmentVariables(), - // expected on development machine - // to override props for dev - file("dev.yaml").optional(), - // expected in k8s runtime - // to configure testing/production values - file("prod.yaml").optional(), - // in jar file - // (see src/main/resources/application.yaml) - classpath("application.yaml"))) - // support for passwords in configuration - //.addFilter(SecureConfigFilter.fromConfig()) - .build(); - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Todo.java b/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Todo.java deleted file mode 100644 index f4262bf5629..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/Todo.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.backend; - -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.UUID; - -import com.datastax.driver.core.Row; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonNumber; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * Data object for backend. - */ -public final class Todo { - - /** - * Date formatter to format the dates of the TODO entries. - */ - private static final DateTimeFormatter DATE_FORMAT = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSVV"); - - /** - * Factory for creating JSON builders. - */ - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - /** - * The TODO ID. - */ - private String id; - - /** - * The user ID associated with this TODO. - */ - private String userId; - - /** - * The TODO title. - */ - private String title; - - /** - * The TODO completed flag. - */ - private Boolean completed; - - /** - * The TODO creation timestamp. - */ - private long created; - - /** - * Create a new {@code Todo} instance from a database entry in JSON format. - * @param jsonObject the database entry - * @return the created instance - */ - public static Todo fromDb(final JsonObject jsonObject) { - - Todo result = new Todo(); - result.id = jsonObject.getString("id"); - result.userId = jsonObject.getString("user"); - result.title = jsonObject.getString("message"); - result.completed = jsonObject.getBoolean("completed"); - result.created = Instant.from(DATE_FORMAT - .parse(jsonObject.getString("created"))).toEpochMilli(); - return result; - } - - /** - * Create a new {@code Todo} instance from a REST entry. - * The created entry will be new, i.e the {@code completed} flag will be set - * to {@code false} and the {@code created} timestamp set to the current - * time. - * @param jsonObject the REST entry - * @param userId the user ID associated with this entry - * @param id the entry ID - * @return the created instance - */ - public static Todo newTodoFromRest(final JsonObject jsonObject, - final String userId, - final String id) { - - Todo result = new Todo(); - result.id = id; - result.userId = userId; - result.title = jsonObject.getString("title"); - result.completed = jsonObject.getBoolean("completed", false); - result.created = System.currentTimeMillis(); - return result; - } - - /** - * Create a new {@code Todo} instance from a REST entry. - * @param jsonObject the REST entry - * @param userId the user ID associated with this entry - * @param id the entry ID - * @return the created instance - */ - public static Todo fromRest(final JsonObject jsonObject, - final String userId, - final String id) { - - Todo result = new Todo(); - result.id = id; - result.userId = userId; - result.title = jsonObject.getString("title", ""); - result.completed = jsonObject.getBoolean("completed"); - JsonNumber created = jsonObject.getJsonNumber("created"); - if (null != created) { - result.created = created.longValue(); - } - return result; - } - - /** - * Create a new {@code Todo} instance from a database entry. - * @param row the database entry - * @return the created instance - */ - public static Todo fromDb(final Row row) { - - Todo result = new Todo(); - result.id = row.getString("id"); - result.userId = row.getString("user"); - result.title = row.getString("message"); - result.completed = row.getBool("completed"); - result.created = row.getTimestamp("created").getTime(); - return result; - } - - /** - * Create a new {@code Todo} instance. - * The created entry will be new, i.e the {@code completed} flag will be set - * to {@code false} and the {@code created} timestamp set to the current - * time. - * @param userId the user ID associated with the new entry - * @param title the title for the new entry - * @return the created instance - */ - public static Todo create(final String userId, final String title) { - Todo result = new Todo(); - - result.id = UUID.randomUUID().toString(); - result.userId = userId; - result.title = title; - result.completed = false; - result.created = System.currentTimeMillis(); - - return result; - } - - /** - * Convert this {@code Todo} instance to the JSON database format. - * @return {@code JsonObject} - */ - public JsonObject forDb() { - //to store to DB - JsonObjectBuilder builder = JSON.createObjectBuilder(); - return builder.add("id", id) - .add("user", userId) - .add("message", title) - .add("completed", completed) - .add("created", created) - .build(); - } - - /** - * Convert this {@code Todo} instance to the JSON REST format. - * @return {@code JsonObject} - */ - public JsonObject forRest() { - //to send over to rest - JsonObjectBuilder builder = JSON.createObjectBuilder(); - return builder.add("id", id) - .add("user", userId) - .add("title", title) - .add("completed", completed) - .add("created", created) - .build(); - } - - /** - * Get the TODO ID. - * @return the {@code String} identifying this entry - */ - public String getId() { - return id; - } - - /** - * Get the user ID associated with this TODO. - * @return the {@code String} identifying the user - */ - public String getUserId() { - return userId; - } - - /** - * Get the TODO title. - * @return title - */ - public String getTitle() { - return title; - } - - /** - * Get the completed flag. - * @return completed flag. - */ - public Boolean getCompleted() { - return completed; - } - - /** - * Set the completed flag. - * @param iscomplete the completed flag value - */ - public void setCompleted(final boolean iscomplete) { - this.completed = iscomplete; - } - - /** - * Get the creation timestamp. - * @return timestamp - */ - public long getCreated() { - return created; - } - - @Override - public String toString() { - return "Todo{" - + "id='" + id + '\'' - + ", userId='" + userId + '\'' - + ", title='" + title + '\'' - + ", completed=" + completed - + ", created=" + created - + '}'; - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/package-info.java b/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/package-info.java deleted file mode 100644 index 55439852c06..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/demo/todos/backend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * TODOs Demo application backend. - */ -package io.helidon.demo.todos.backend; diff --git a/examples/todo-app/backend/src/main/resources/META-INF/beans.xml b/examples/todo-app/backend/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/todo-app/backend/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/todo-app/backend/src/main/resources/application.yaml b/examples/todo-app/backend/src/main/resources/application.yaml deleted file mode 100644 index cebe7db0a75..00000000000 --- a/examples/todo-app/backend/src/main/resources/application.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -env: docker - -server: - port: 8854 - host: 0.0.0.0 - -tracing: - service: "todo:back" - port: 9411 - -cassandra: - port: 9042 - servers: - - host: "localhost" - -security: - config: - require-encryption: false - aes.insecure-passphrase: "jungle" - provider-policy: - type: "COMPOSITE" - authentication: - - name: "google-login" - - name: "http-signatures" - providers: - - google-login: - client-id: "1048216952820-6a6ke9vrbjlhngbc0al0dkj9qs9tqbk2.apps.googleusercontent.com" - - abac: - - http-signatures: - inbound.keys: - - key-id: "frontend" - principal-name: "Frontend Service" - hmac.secret: "${CLEAR=frontend2backend}" diff --git a/examples/todo-app/backend/src/main/resources/logging.properties b/examples/todo-app/backend/src/main/resources/logging.properties deleted file mode 100644 index a77b4c191f6..00000000000 --- a/examples/todo-app/backend/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -#All attributes details -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#All log level details -.level=WARNING -io.helidon.webserver.level=INFO -io.helidon.security.level=INFO -io.helidon.tracing.level=FINE -AUDIT.level=FINEST - - diff --git a/examples/todo-app/backend/src/test/java/io/helidon/demo/todos/backend/BackendTests.java b/examples/todo-app/backend/src/test/java/io/helidon/demo/todos/backend/BackendTests.java deleted file mode 100644 index 1dd5cdeb6c1..00000000000 --- a/examples/todo-app/backend/src/test/java/io/helidon/demo/todos/backend/BackendTests.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.backend; - -import java.io.IOException; -import java.util.Base64; -import java.util.Properties; - -import io.helidon.common.http.Http; -import io.helidon.config.mp.MpConfigSources; -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.microprofile.tests.junit5.Configuration; -import io.helidon.microprofile.tests.junit5.HelidonTest; - -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Session; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -@Configuration(useExisting = true) -// Embedded cassandra does not start on Java 17 -@Disabled("3.0.0-JAKARTA") -class BackendTests { - - private final static String CASSANDRA_HOST = "127.0.0.1"; - - @Inject - private WebTarget webTarget; - - @BeforeAll - static void init() throws IOException { - Properties cassandraProperties = initCassandra(); - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - ConfigProviderResolver configResolver = ConfigProviderResolver.instance(); - - org.eclipse.microprofile.config.Config mpConfig = configResolver.getBuilder() - .withSources(YamlMpConfigSource.create(cl.getResource("test-application.yaml")), - MpConfigSources.create(cassandraProperties)) - .build(); - - configResolver.registerConfig(mpConfig, null); - } - - @AfterAll - static void stopServer() { - EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); - } - - private static Properties initCassandra() throws IOException { - EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.CASSANDRA_RNDPORT_YML_FILE, - 20000L); - Properties prop = new Properties(); - prop.put("cassandra.port", String.valueOf(EmbeddedCassandraServerHelper.getNativeTransportPort())); - prop.put("cassandra.servers.host.host", CASSANDRA_HOST); - - Cluster cluster = Cluster.builder() - .withoutMetrics() - .addContactPoint(CASSANDRA_HOST) - .withPort(EmbeddedCassandraServerHelper.getNativeTransportPort()) - .build(); - - Session session = cluster.connect(); - session.execute("CREATE KEYSPACE backend WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1};"); - session.execute( - "CREATE TABLE backend.backend (id ascii, user ascii, message ascii, completed Boolean, created timestamp, " - + "PRIMARY KEY (id));"); - session.execute("select * from backend.backend;"); - - session.close(); - cluster.close(); - - return prop; - } - - @Test - void testTodoScenario() { - String basicAuth = "Basic " + Base64.getEncoder().encodeToString("john:password".getBytes()); - JsonObject todo = Json.createObjectBuilder() - .add("title", "todo title") - .build(); - - // Add a new todo - JsonObject returnedTodo = webTarget - .path("/api/backend") - .request(MediaType.APPLICATION_JSON_TYPE) - .header(Http.Header.AUTHORIZATION, basicAuth) - .post(Entity.json(todo), JsonObject.class); - - assertThat(returnedTodo.getString("user"), is("john")); - assertThat(returnedTodo.getString("title"), is(todo.getString("title"))); - - // Get the todo created earlier - JsonObject fromServer = webTarget.path("/api/backend/" + returnedTodo.getString("id")) - .request(MediaType.APPLICATION_JSON_TYPE) - .header(Http.Header.AUTHORIZATION, basicAuth) - .get(JsonObject.class); - - assertThat(fromServer, is(returnedTodo)); - - // Update the todo created earlier - JsonObject updatedTodo = Json.createObjectBuilder() - .add("title", "updated title") - .add("completed", false) - .build(); - - fromServer = webTarget.path("/api/backend/" + returnedTodo.getString("id")) - .request(MediaType.APPLICATION_JSON_TYPE) - .header(Http.Header.AUTHORIZATION, basicAuth) - .put(Entity.json(updatedTodo), JsonObject.class); - - assertThat(fromServer.getString("title"), is(updatedTodo.getString("title"))); - - // Delete the todo created earlier - fromServer = webTarget.path("/api/backend/" + returnedTodo.getString("id")) - .request(MediaType.APPLICATION_JSON_TYPE) - .header(Http.Header.AUTHORIZATION, basicAuth) - .delete(JsonObject.class); - - assertThat(fromServer.getString("id"), is(returnedTodo.getString("id"))); - - // Get list of todos - JsonArray jsonValues = webTarget.path("/api/backend") - .request(MediaType.APPLICATION_JSON_TYPE) - .header(Http.Header.AUTHORIZATION, basicAuth) - .get(JsonArray.class); - - assertThat("There should be no todos on server", jsonValues.size(), is(0)); - } - -} diff --git a/examples/todo-app/backend/src/test/resources/test-application.yaml b/examples/todo-app/backend/src/test/resources/test-application.yaml deleted file mode 100644 index aa071626dd7..00000000000 --- a/examples/todo-app/backend/src/test/resources/test-application.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# increase importance -config_ordinal: 500 - -# we use custom config and Helidon JUnit integration, must allow initializer -mp: - initializer: - allow: true - no-warn: true - -server: - port: 0 - host: localhost - -tracing: - service: "todo:back" - enabled: false - -security: - providers: - - http-basic-auth: - realm: "helidon" - users: - - login: "john" - password: "password" diff --git a/examples/todo-app/cassandra/Dockerfile b/examples/todo-app/cassandra/Dockerfile deleted file mode 100644 index 81b8c7a5daa..00000000000 --- a/examples/todo-app/cassandra/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2017, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM cassandra:3.11.16 - -ADD startup.sh / - -RUN chmod -v u=rx,og-rwx /startup.sh - -ENTRYPOINT ["/startup.sh"] - -EXPOSE 7000 7001 7199 9042 9160 - -CMD ["cassandra", "-f"] diff --git a/examples/todo-app/cassandra/startup.sh b/examples/todo-app/cassandra/startup.sh deleted file mode 100644 index ca6aaa6d901..00000000000 --- a/examples/todo-app/cassandra/startup.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -set -e - -echo 'Starting Cassandra database' -/docker-entrypoint.sh "$@" > /var/log/cassandra.log & - -echo 'Waiting for database to become available' -COUNT='1' -while test $COUNT -lt '120' && ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/9042' > /dev/null 2>&1 ; do - if [ "$((COUNT%10))" -eq '0' ]; then - echo " ...$COUNT s" - fi - sleep 1 - COUNT=$((COUNT+1)) -done - -echo 'Creating todos table' -cqlsh -e " - CREATE KEYSPACE backend WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1}; - CREATE TABLE backend.backend (id ascii, user ascii, message ascii, completed Boolean, created timestamp, PRIMARY KEY (id)); - select * from backend.backend; -" \ - || true - -echo 'Opening database log file' -echo '-------------------------' -tail -f /var/log/cassandra.log diff --git a/examples/todo-app/frontend/pom.xml b/examples/todo-app/frontend/pom.xml deleted file mode 100644 index 7e20b967573..00000000000 --- a/examples/todo-app/frontend/pom.xml +++ /dev/null @@ -1,158 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.todo - helidon-examples-todo-frontend - Helidon Examples TODO Demo Frontend - - - Front-end part of the application, uses Helidon SE - - - - io.helidon.demo.todos.frontend.Main - ${mainClass} - - - - - io.helidon.common - helidon-common - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-security - - - io.helidon.webclient - helidon-webclient-tracing - - - io.helidon.webserver - helidon-webserver-access-log - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing - helidon-tracing-zipkin - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security - helidon-security - - - io.helidon.security.providers - helidon-security-providers-google-login - - - io.helidon.security.providers - helidon-security-providers-abac - - - io.helidon.security.providers - helidon-security-providers-http-sign - - - io.helidon.security.integration - helidon-security-integration-webserver - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - - - io.helidon.security.providers - helidon-security-providers-http-auth - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/BackendServiceClient.java b/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/BackendServiceClient.java deleted file mode 100644 index 667a853f5b0..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/BackendServiceClient.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2017, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.frontend; - -import java.util.function.Function; - -import io.helidon.common.http.Http.ResponseStatus.Family; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webclient.tracing.WebClientTracing; -import io.helidon.webserver.HttpException; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; - -/** - * Client to invoke the backend service. - */ -final class BackendServiceClient { - - private final WebClient client; - - BackendServiceClient(Config config) { - String serviceEndpoint = config.get("services.backend.endpoint").asString().get(); - this.client = WebClient.builder() - .useSystemServiceLoader(false) - .addService(WebClientTracing.create()) - .addService(WebClientSecurity.create()) - .addMediaSupport(JsonpSupport.create()) - .baseUri(serviceEndpoint + "/api/backend").build(); - } - - /** - * Retrieve all entries from the backend. - * - * @return single with all records - */ - Single list() { - return client.get() - .request() - .flatMapSingle(processResponse(JsonArray.class)); - } - - /** - * Retrieve the entry identified by the given ID. - * - * @param id the ID identifying the entry to retrieve - * @return retrieved entry as a {@code JsonObject} - */ - Single get(String id) { - return client.get() - .path(id) - .request() - .flatMapSingle(processResponse(JsonObject.class)); - } - - /** - * Delete the entry identified by the given ID. - * - * @param id the ID identifying the entry to delete - * @return deleted entry as a {@code JsonObject} - */ - Single deleteSingle(String id) { - return client.delete() - .path(id) - .request() - .flatMapSingle(processResponse(JsonObject.class)); - } - - /** - * Create a new entry. - * - * @param json the new entry value to create as {@code JsonObject} - * @return created entry as {@code JsonObject} - */ - Single create(JsonObject json) { - return client.post() - .submit(json) - .flatMapSingle(processResponse(JsonObject.class)); - } - - /** - * Update an entry identified by the given ID. - * - * @param id the ID identifying the entry to update - * @param json the update entry value as {@code JsonObject} - * @return updated entry as {@code JsonObject} - */ - Single update(String id, JsonObject json) { - return client.put() - .path(id) - .submit(json) - .flatMapSingle(processResponse(JsonObject.class)); - } - - private Function> processResponse(Class clazz) { - return response -> { - if (response.status().family() != Family.SUCCESSFUL) { - return Single.error(new HttpException("backend error", response.status())); - } - return response.content().as(clazz); - }; - } -} diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/Main.java b/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/Main.java deleted file mode 100644 index 5e37f82a61d..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/Main.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2017, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.frontend; - -import java.time.Duration; -import java.util.List; - -import io.helidon.common.LogConfig; -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.config.FileSystemWatcher; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.security.Security; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.tracing.Tracer; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.accesslog.AccessLogSupport; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.environmentVariables; -import static io.helidon.config.ConfigSources.file; -import static io.helidon.config.PollingStrategies.regular; - -/** - * Main class to start the service. - */ -public final class Main { - - /** - * Interval for config polling. - */ - private static final Long POLLING_INTERVAL = 5L; - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments - */ - public static void main(final String[] args) { - - // load logging configuration - LogConfig.configureRuntime(); - - Config config = buildConfig(); - - Security security = Security.create(config.get("security")); - - // create a web server - WebServer server = WebServer.builder() - .addRouting(createRouting(security, config)) - .config(config.get("webserver")) - .addMediaSupport(JsonpSupport.create()) - .tracer(registerTracer(config)) - .build(); - - // start the web server - server.start().whenComplete(Main::started); - } - - /** - * Create a {@code Tracer} instance using the given {@code Config}. - * @param config the configuration root - * @return the created {@code Tracer} - */ - private static Tracer registerTracer(Config config) { - return TracerBuilder.create(config.get("tracing")).build(); - } - - /** - * Create the web server routing and register all handlers. - * @param security the security features - * @param config the configuration root - * @return the created {@code Routing} - */ - private static Routing createRouting(Security security, Config config) { - return Routing.builder() - .register(AccessLogSupport.create()) - // register metrics features (on "/metrics") - .register(MetricsSupport.create()) - // register security features - .register(WebSecurity.create(security, config.get("security"))) - // redirect POST / to GET / - .post("/", (req, res) -> { - res.addHeader(Http.Header.LOCATION, "/"); - res.status(Http.Status.SEE_OTHER_303); - res.send(); - }) - // register static content support (on "/") - .register(StaticContentSupport.builder("/WEB").welcomeFileName("index.html")) - // register API handler (on "/api") - this path is secured (see application.yaml) - .register("/api", new TodoService(new BackendServiceClient(config))) - .build(); - } - - /** - * Handle web server started event: if successful print server started - * message in the console with the corresponding URL, otherwise print an - * error message and exit the application. - * @param webServer the {@code WebServer} instance - * @param throwable if non {@code null}, indicate a server startup error - */ - private static void started(WebServer webServer, Throwable throwable) { - if (throwable == null) { - System.out.println("WEB server is up! http://localhost:" + webServer.port()); - } else { - throwable.printStackTrace(System.out); - System.exit(1); - } - } - - /** - * Load the configuration from all sources. - * @return the configuration root - */ - private static Config buildConfig() { - return Config.builder() - .sources(List.of( - environmentVariables(), - // expected on development machine - // to override props for dev - file("dev.yaml") - .changeWatcher(FileSystemWatcher.create()) - .optional(), - // expected in k8s runtime - // to configure testing/production values - file("prod.yaml") - .pollingStrategy(regular(Duration.ofSeconds(POLLING_INTERVAL))) - .optional(), - // in jar file - // (see src/main/resources/application.yaml) - classpath("application.yaml"))) - .build(); - } -} diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/TodoService.java b/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/TodoService.java deleted file mode 100644 index d12468005e1..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/TodoService.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.demo.todos.frontend; - -import io.helidon.common.http.Http; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.JsonObject; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.Metadata; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.MetricType; -import org.eclipse.microprofile.metrics.MetricUnits; - -/** - * TODO service. - *

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

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

- * Here is a summary of the operations: - * GET /api/todo: Get all entries - * GET /api/todo/{id}: Get an entry by ID - * POST /api/todo: Create a new entry, created entry is returned - * DELETE /api/todo/{id}: Delete an entry, deleted entry is returned - * PUT /api/todo/{id}: Update an entry, updated entry is returned - */ -public final class TodoService implements Service { - - private final BackendServiceClient bsc; - private final Counter createCounter; - private final Counter updateCounter; - private final Counter deleteCounter; - - /** - * Create a new {@code TodosHandler} instance. - * - * @param bsc the {@code BackendServiceClient} to use - */ - TodoService(BackendServiceClient bsc) { - MetricRegistry registry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); - this.bsc = bsc; - this.createCounter = registry.counter("created"); - this.updateCounter = registry.counter("updates"); - this.deleteCounter = registry.counter(Metadata.builder() - .withName("deletes") - .withDisplayName("deletes") - .withDescription("Number of deleted todos") - .withType(MetricType.COUNTER) - .withUnit(MetricUnits.NONE) - .build()); - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/todo/{id}", this::get) - .delete("/todo/{id}", this::delete) - .put("/todo/{id}", this::update) - .get("/todo", this::list) - .post("/todo", this::create); - } - - /** - * Handler for {@code POST /todo}. - * - * @param req the server request - * @param res the server response - */ - private void create(ServerRequest req, ServerResponse res) { - req.content() - .as(JsonObject.class) - .flatMapSingle(bsc::create) - .peek(ignored -> createCounter.inc()) - .onError(res::send) - .forSingle(json -> { - res.status(Http.Status.CREATED_201); - res.send(json); - }); - } - - /** - * Handler for {@code GET /todo}. - * - * @param req the server request - * @param res the server response - */ - private void list(ServerRequest req, ServerResponse res) { - bsc.list() - .onError(res::send) - .forSingle(res::send); - } - - /** - * Handler for {@code PUT /todo/id}. - * - * @param req the server request - * @param res the server response - */ - private void update(ServerRequest req, ServerResponse res) { - req.content() - .as(JsonObject.class) - .flatMapSingle(json -> bsc.update(req.path().param("id"), json)) - .peek(ignored -> updateCounter.inc()) - .onError(res::send) - .forSingle(res::send); - } - - /** - * Handler for {@code DELETE /todo/id}. - * - * @param req the server request - * @param res the server response - */ - private void delete(ServerRequest req, ServerResponse res) { - bsc.deleteSingle(req.path().param("id")) - .peek(ignored -> deleteCounter.inc()) - .onError(res::send) - .forSingle(res::send); - } - - /** - * Handler for {@code GET /todo/id}. - * - * @param req the server request - * @param res the server response - */ - private void get(ServerRequest req, ServerResponse res) { - bsc.get(req.path().param("id")) - .onError(res::send) - .forSingle(res::send); - } -} diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/package-info.java b/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/package-info.java deleted file mode 100644 index 666616a7b8c..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/demo/todos/frontend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * TODOs Demo application frontend. - */ -package io.helidon.demo.todos.frontend; diff --git a/examples/todo-app/frontend/src/main/resources/WEB/css/styles.css b/examples/todo-app/frontend/src/main/resources/WEB/css/styles.css deleted file mode 100644 index 0a3e16b4e9f..00000000000 --- a/examples/todo-app/frontend/src/main/resources/WEB/css/styles.css +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -html, -body { - margin: 0 auto; - padding: 0; - font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; - line-height: 1.4em; - background: #f5f5f5; - color: #4d4d4d; - min-width: 600px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-weight: 300; -} - -input { - font-family: inherit; - font-weight: inherit; - color: inherit; - border: 0; -} - -button { - margin: 0; - padding: 0; - border: 0; - background: none; - font-size: 100%; - vertical-align: baseline; - font-family: inherit; - font-weight: inherit; - color: inherit; - cursor: pointer; - -webkit-appearance: none; - appearance: none; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -:focus { - outline: 0; -} - -.hidden { - display: none; -} - -nav { - display: flex; - align-items: center; - padding: 0 20px 0 20px; - height: 80px; -} - -.spacer { - flex-grow: 1; -} - -.row { - display: flex; - flex-direction: row; - align-items: center; -} - -.column { - display: flex; - flex-direction: column; - align-items: center; -} - -.wrap { - display: none; -} - -.todoapp { - width: 550px; - background: #fff; - margin: 130px 0 40px 0; - position: relative; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), - 0 25px 50px 0 rgba(0, 0, 0, 0.1); -} - -.todoapp input::-webkit-input-placeholder { - font-style: italic; - font-weight: 300; - color: #e6e6e6; -} - -.todoapp input::-moz-placeholder { - font-style: italic; - font-weight: 300; - color: #e6e6e6; -} - -.todoapp h1 { - position: absolute; - top: -155px; - width: 100%; - font-size: 100px; - font-weight: 100; - text-align: center; - color: rgba(175, 47, 47, 0.15); - text-rendering: optimizeLegibility; -} - -.new-todo { - position: relative; - margin: 0; - width: 100%; - font-size: 24px; - font-family: inherit; - font-weight: inherit; - line-height: 1.4em; - color: inherit; - padding: 6px; - border: 1px solid #999; - box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); - box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.new-todo { - padding: 16px 16px 16px 60px; - border: none; - background: rgba(0, 0, 0, 0.003); - box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03); -} - -.main { - position: relative; - z-index: 2; - border-top: 1px solid #e6e6e6; -} - -.checkbox { - border: none; /* Mobile Safari */ - appearance: none; - opacity: 0.25; - -webkit-appearance: none; - margin: 10px; -} - -.checkbox:after { - font-family: 'Material Symbols Outlined'; - font-size: 25px; - transition: opacity 0.2s ease-out; - cursor: pointer; -} - -.checkbox:hover { - opacity: 0.5; -} - -.checkbox:active { - opacity: 0.75; -} - -.toggle-all:after { - content: "\e877"; -} - -.todo-list { - margin: 0; - padding: 0; - list-style: none; -} - -.todo-list li { - position: relative; - font-size: 24px; - border-bottom: 1px solid #ededed; -} - -.todo-list li:last-child { - border-bottom: none; -} - -.todo-list .view, .todo-list .edit { - flex-grow: 1; - padding: 15px 15px 15px 60px; - line-height: 1.2; - font-size: 24px; -} - -.todo-list li.editing { - padding: 0; -} - -.todo-list li.editing .edit { - display: block; -} - -.todo-list li.editing .view { - display: none; -} - -.todo-list li .toggle { - margin: 10px; - display: flex; - align-items: center; -} - -.toggle:after { - content: "\ef4a"; -} - -.toggle:checked:after { - content: "\e86c"; -} - -.todo-list li label { - word-break: break-all; - padding: 15px 15px 15px 60px; - display: block; - line-height: 1.2; - transition: color 0.4s; -} - -.todo-list li.completed label { - color: #d9d9d9; - text-decoration: line-through; -} - -.todo-list li .actions { - display: flex; - align-items: center; - margin: 10px; -} - -.todo-list li .actions button { - margin: 5px; - opacity: 0.25; - font-size: 0; - cursor: pointer; - transition: opacity 0.2s ease-out; -} - -.todo-list li .actions button:hover { - opacity: 0.5; -} - -.todo-list li .actions button:active { - opacity: 0.75; -} - -.todo-list li .actions button:before { - font-family: 'Material Symbols Outlined'; - font-size: 25px; -} - -.todo-list li .actions .update:before { - content: '\e3c9' -} - -.todo-list li.editing .actions .update:before { - content: '\e5ca' !important; -} - -.todo-list li .actions .delete:before { - content: '\e872' -} - -.todo-list li .edit { - display: none; -} - -.todo-list li.editing:last-child { - margin-bottom: -1px; -} - -.footer { - color: #777; - padding: 10px 15px; - height: 20px; - text-align: center; - border-top: 1px solid #e6e6e6; -} - -.footer:before { - content: ''; - position: absolute; - right: 0; - bottom: 0; - left: 0; - height: 50px; - overflow: hidden; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), - 0 8px 0 -3px #f6f6f6, - 0 9px 1px -3px rgba(0, 0, 0, 0.2), - 0 16px 0 -6px #f6f6f6, - 0 17px 2px -6px rgba(0, 0, 0, 0.2); -} - -.todo-count { - float: left; - text-align: left; -} - -.todo-count strong { - font-weight: 300; -} - -.filters { - margin: 0; - padding: 0; - list-style: none; - position: absolute; - right: 0; - left: 0; -} - -.filters li { - display: inline; -} - -.filters li a { - color: inherit; - margin: 3px; - padding: 3px 7px; - text-decoration: none; - border: 1px solid transparent; - border-radius: 3px; -} - -.filters li a:hover { - border-color: rgba(175, 47, 47, 0.1); -} - -.filters li a.selected { - border-color: rgba(175, 47, 47, 0.2); -} - -.clear-completed, html .clear-completed:active { - float: right; - position: relative; - line-height: 20px; - text-decoration: none; - cursor: pointer; -} - -.clear-completed:hover { - text-decoration: underline; -} - -.info { - margin: 0; - color: #bfbfbf; - font-size: 14px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - text-align: center; -} - -.info p { - line-height: 1; -} - -.info a { - color: inherit; - text-decoration: none; - font-weight: 400; -} - -.info a:hover { - text-decoration: underline; -} - -@media screen and (-webkit-min-device-pixel-ratio: 0) { - .toggle-all, .todo-list li .toggle { - background: none; - } - - .todo-list li .toggle { - height: 40px; - } -} - -@media (max-width: 430px) { - .footer { - height: 50px; - } - - .filters { - bottom: 10px; - } -} - -#user-info { - display:none; -} - -#user-info > div { - display:flex; -} - -#user-info .sign-out { - margin-right: 10px; - background: white; - padding: 5px; - border: 1px solid #dadce0; - border-radius: 4px; - transition: background-color .218s, border-color .218s; -} - -#user-info .sign-out:hover { - border-color: #d2e3fc; - background-color: rgba(66,133,244,.04); -} -#user-info .sign-out:active { - background-color: rgba(66,133,244,.1); -} diff --git a/examples/todo-app/frontend/src/main/resources/WEB/index.html b/examples/todo-app/frontend/src/main/resources/WEB/index.html deleted file mode 100644 index cadce1e3c09..00000000000 --- a/examples/todo-app/frontend/src/main/resources/WEB/index.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - Helidon TodoMVC - - - - -

-
-
-
-
-

todos

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

    Helidon implementation of TodoMVC

    -
    -
    - - - - - - - - - diff --git a/examples/todo-app/frontend/src/main/resources/WEB/js/app.js b/examples/todo-app/frontend/src/main/resources/WEB/js/app.js deleted file mode 100644 index 7a4d5ac952d..00000000000 --- a/examples/todo-app/frontend/src/main/resources/WEB/js/app.js +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* global jQuery, Router */ - -/** - * @typedef {Object} Handlebars - * @property {function(string, function(*, *, HandlebarsOpts))} registerHelper - * @property {function(HTMLElement):function(object):string} compile - */ - -/** - * @typedef {Object} HandlebarsOpts - * @property {function(object)} fn - * @property {function(object)} inverse - */ - -/** - * @typedef {Object} Google - * @property {GoogleAccount} accounts - */ - -/** - * @typedef {Object} GoogleAccount - * @property {GoogleId} id - */ - -/** - * @typedef {Object} GoogleId - * @property {function({})} initialize - * @property {function()} prompt - * @property {function(Element, Object)} renderButton - * @property {function(string} revoke - */ - -/** - * @typedef {Object} Todo - * @property {string} title - * @property {string=} id - * @property {boolean} completed - */ - -class TodoClient { - - constructor(access_token) { - this.access_token = access_token - } - - /** - * List all entries. - * @return {Promise} - */ - list() { - return this._ajax('GET', '/api/todo'); - } - - /** - * Create a new entry. - * @property {Todo} data - * @return {Promise} - */ - create(item) { - return this._ajax('POST', '/api/todo', item); - } - - /** - * Toggle an entry. - * @param {Todo} item - * @param {boolean} completed - */ - toggle(item, completed) { - const data = {...item, completed}; - return this._ajax('PUT', `/api/todo/${item.id}`, data); - } - - /** - * Update an entry. - * @param {Todo} item - * @return {Promise} - */ - update(item) { - return this._ajax('PUT', `/api/todo/${item.id}`, item); - } - - /** - * Delete an entry. - * @param {string} id - * @return {Promise} - */ - delete(id) { - return this._ajax('DELETE', `/api/todo/${id}`); - } - - /** - * Batch requests. - * @param {Todo[]} items - * @param {function(Todo):boolean} filter - * @param {function(Todo, number): Promise} fn - * @return {Promise[]>} - */ - batch(items, filter, fn) { - const promises = []; - items.forEach((e, i) => { - if (filter(e)) { - promises.push(fn(e, i)); - } - }) - return Promise.all(promises); - } - - /** - * Toggle all items. - * @property {Todo[]} items - * @property {boolean} completed - * @return {Promise} - */ - toggleAll(items, completed) { - const result = [...items]; - return this.batch(items, e => e.completed !== completed, (e, i) => { - return this.toggle(e, completed).then(data => { - result[i] = data; - }) - }).then(() => result); - } - - /** - * Delete all completed items. - * @param {Todo[]} items - * @return {Promise} - */ - deleteCompleted(items) { - const indexes = []; - const result = [...items]; - return this.batch(items, e => e.completed, (data, index) => { - indexes.push(index); - return this._ajax('DELETE', `/api/todo/${data.id}`); - }).then(() => { - indexes.sort(); - for (let i = indexes.length - 1; i >= 0; i--) { - result.splice(indexes[i], 1); - } - return result; - }) - } - - /** - * @param {string} type - * @param {string} path - * @param {object=} data - * @return {Promise} - */ - _ajax(type, path, data) { - while (path.startsWith('/')) { - path = path.substring(1); - } - return new Promise((resolve, reject) => { - // noinspection JSUnusedGlobalSymbols - $.ajax({ - type: type, - beforeSend: (request) => { - if (this.access_token) { - request.setRequestHeader('Authorization', `Bearer ${this.access_token}`); - } - }, - url: window.location.pathname + path, - dataType: 'json', - contentType: 'application/json;charset=utf-8', - data: data && JSON.stringify(data) - }).done((resData) => { - resolve(resData); - }).fail((data, textStatus) => { - reject(textStatus); - }); - }) - } -} - -class App { - - constructor() { - this.client = null; - this.token = null; - this.todos = []; - this.todoTemplate = Handlebars.compile($('#todo-template').html()); - this.footerTemplate = Handlebars.compile($('#footer-template').html()); - this.router = new Router({ - '/:filter': (filter) => { - this.filter = filter; - this.render(); - } - }); - $('.sign-out').on('click', e => this.signOut()); - $('.new-todo').on('keyup', e => this.create(e)); - $('.toggle-all').on('change', e => this.toggleAll(e)); - $('.footer').on('click', '.clear-completed', () => this.deleteCompleted()); - $('.todo-list') - .on('change', '.toggle', e => this.toggle(e)) - .on('click', '.update', e => this.editingMode(e)) - .on('focusout', '.edit', e => this.update(e)) - .on('click', '.delete', e => this.destroy(e)); - } - - signOut() { - const google = /** @type {Google} */ (window['google']); - google.accounts.id.revoke(this.token.sub); - this.client = null; - this.token = null; - $('#user-info').fadeOut(); - $('.wrap').fadeOut(); - google.accounts.id.prompt(); - } - - /** - * Init the application. - */ - init(access_token) { - this.client = new TodoClient(access_token); - this.token = JSON.parse(atob(access_token.split(".")[1])); - const signedIn = access_token && true || false; - if (signedIn) { - this.init0().then(() => { - $('.wrap').fadeIn(); - $('#user-info').fadeIn(); - }) - } - } - - init0() { - return this.client.list().then(items => { - this.todos = items; - this.router.init('/all'); - }).catch(console.error); - } - - /** - * Render. - */ - render() { - const todos = this.getFilteredTodos(); - $('.todo-list').html(this.todoTemplate(todos.map((e, i) => { - e.index = i; - return e; - }))); - $('.main').toggle(todos.length > 0); - $('.toggle-all').prop('checked', this.getActiveTodos().length === 0); - this.renderFooter(); - $('.new-todo').focus(); - } - - /** - * Render the footer. - */ - renderFooter() { - const todoCount = this.todos.length; - const activeTodoCount = this.getActiveTodos().length; - const template = this.footerTemplate({ - activeTodoCount: activeTodoCount, - activeTodoWord: this.pluralize(activeTodoCount, 'item'), - completedTodos: todoCount - activeTodoCount, - filter: this.filter - }); - $('.footer').toggle(todoCount > 0).html(template); - } - - /** - * Pluralize the given word. - * @param {number} count - * @param {string} word - * @return {string} - */ - pluralize(count, word) { - return count === 1 ? word : word + 's'; - } - - /** - * Get the active entries. - * @return {Todo[]} - */ - getActiveTodos() { - return this.todos.filter((todo) => { - return !todo.completed; - }); - } - - /** - * Get the completed entries. - * @return {Todo[]} - */ - getCompletedTodos() { - return this.todos.filter((todo) => todo.completed); - } - - /** - * Get the entries for the current filter. - * @return {Todo[]} - */ - getFilteredTodos() { - if (this.filter === 'active') { - return this.getActiveTodos(); - } - if (this.filter === 'completed') { - return this.getCompletedTodos(); - } - return this.todos; - } - - /** - * Toggle all entries. - * @param {Event} e - */ - toggleAll(e) { - const isChecked = $(e.target).prop('checked'); - this.client.toggleAll(this.todos, isChecked).then(items => { - this.todos = items; - this.render(); - }).catch(console.error); - } - - /** - * Delete all completed entries. - */ - deleteCompleted() { - this.client.deleteCompleted(this.todos).then(items => { - this.todos = items; - this.render(); - }).catch(console.error); - } - - /** - * Create a new entry. - * @param {KeyboardEvent} e - */ - create(e) { - const input = $(e.target); - const val = input.val().trim(); - if (e.key !== "Enter" || !val) { - return; - } - input.val(''); - const item = {title: val, completed: false}; - this.client.create(item).then((data) => { - this.todos.push(data); - this.render(); - }).catch(console.error) - } - - /** - * Toggle an entry. - * @param {Event} e - * @return {Promise} - */ - toggle(e) { - const info = this.entryInfo(e.target); - const entry = this.todos[info.index]; - return this.client.toggle(entry, !entry.completed).then((data) => { - this.todos[info.index] = data; - this.render(); - }).catch(console.error); - } - - /** - * Update an entry. - * @param {{target: Element}} e - * @return {Promise} - */ - update(e) { - const input = $(e.target); - const val = input.val().trim(); - if (!val) { - this.destroy(e); - return Promise.resolve(); - } else { - const info = this.entryInfo(e.target); - const newData = {...this.todos[info.index], title: val}; - return this.client.update(newData).then(data => { - this.todos[info.index] = data; - this.render(); - }).catch(console.error); - } - } - - /** - * Destroy an entry. - * @param {{target: Element}} e - */ - destroy(e) { - const info = this.entryInfo(e.target); - this.client.delete(info.id).then(() => { - this.todos.splice(info.index, 1); - this.render(); - }).catch(console.error); - } - - /** - * Edit an entry. - * @param {Event} e - */ - editingMode(e) { - const listElt = $(e.target).closest('li'); - const editing = listElt.hasClass('editing'); - if (editing) { - const input = listElt.find('.edit'); - this.update({ - target: input[0] - }).then(() => listElt.removeClass('editing')); - } else { - const input = listElt.addClass('editing').find('.edit'); - // puts caret at end of input - const tmpStr = input.val(); - input.val(''); - input.val(tmpStr); - input.focus(); - } - } - - /** - * Get the entry info for an element. - * @param {Element} el - * @return {{index: number, id: string}} - */ - entryInfo(el) { - const id = $(el).closest('li').data('id'); - const todos = this.todos; - let i = todos.length; - while (i--) { - if (todos[i].id === id) { - return {id, index: i}; - } - } - } -} - -window.onload = () => { - const google = /** @type {Google} */ (window['google']); - const Handlebars = /** @type {Handlebars} */ (window['Handlebars']); - - Handlebars.registerHelper('eq', (a, b, options) => { - return a === b ? options.fn(this) : options.inverse(this); - }); - - const app = new App(); - - // noinspection JSUnusedGlobalSymbols,SpellCheckingInspection - google.accounts.id.initialize({ - client_id: '1048216952820-6a6ke9vrbjlhngbc0al0dkj9qs9tqbk2.apps.googleusercontent.com', - auto_select: true, - callback: response => { - app.init(response.credential) - } - }); - google.accounts.id.prompt(); -} diff --git a/examples/todo-app/frontend/src/main/resources/application.yaml b/examples/todo-app/frontend/src/main/resources/application.yaml deleted file mode 100644 index d6459c14b13..00000000000 --- a/examples/todo-app/frontend/src/main/resources/application.yaml +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -env: docker - -webserver: - port: 8080 - -cors: - allow-origins: ["https://cdnjs.cloudflare.com", "https://raw.githubusercontent.com"] - allow-methods: ["GET"] - -tracing: - service: "todo:front" - port: 9411 - -services: - backend.endpoint: "http://localhost:8854" - -security: - config: - require-encryption: false - aes.insecure-passphrase: "jungle" - provider-policy: - type: "COMPOSITE" - authentication: - - name: "google-login" - outbound: - - name: "google-login" - - name: "http-signatures" - providers: - - google-login: - client-id: "1048216952820-6a6ke9vrbjlhngbc0al0dkj9qs9tqbk2.apps.googleusercontent.com" - outbound: - - name: "backend" - hosts: [ "localhost" ] - - abac: - - http-signatures: - outbound: - - name: "backend" - hosts: [ "localhost" ] - signature: - key-id: "frontend" - hmac.secret: "${CLEAR=frontend2backend}" - web-server: - paths: - - path: "/api/{+}" - authenticate: true diff --git a/examples/todo-app/frontend/src/main/resources/logging.properties b/examples/todo-app/frontend/src/main/resources/logging.properties deleted file mode 100644 index a77b4c191f6..00000000000 --- a/examples/todo-app/frontend/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -#All attributes details -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#All log level details -.level=WARNING -io.helidon.webserver.level=INFO -io.helidon.security.level=INFO -io.helidon.tracing.level=FINE -AUDIT.level=FINEST - - diff --git a/examples/todo-app/frontend/src/test/java/io/helidon/demo/todos/frontend/TodoServiceTest.java b/examples/todo-app/frontend/src/test/java/io/helidon/demo/todos/frontend/TodoServiceTest.java deleted file mode 100644 index 1a65b19d72f..00000000000 --- a/examples/todo-app/frontend/src/test/java/io/helidon/demo/todos/frontend/TodoServiceTest.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.demo.todos.frontend; - -import java.time.Duration; -import java.util.Base64; -import java.util.List; -import java.util.Map; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.security.Security; -import io.helidon.security.integration.webserver.WebSecurity; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.config.ConfigSources.classpath; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -public class TodoServiceTest { - - private static final JsonObject TODO = Json.createObjectBuilder().add("msg", "todo").build(); - private static final JsonArray TODOS = Json.createArrayBuilder().add(TODO).build(); - private static final String ENCODED_ID = Base64.getEncoder().encodeToString("john:password".getBytes()); - - private static WebServer serverBackend; - private static WebServer serverFrontend; - private static WebClient client; - - private static class BackendServiceMock implements Service { - - @Override - public void update(Routing.Rules rules) { - rules.get("/", this::list) - .get("/{id}", this::get) - .delete("/{id}", this::get) - .post(this::echo) - .put("/{id}", this::echo); - } - - void list(ServerRequest req, ServerResponse res) { - res.send(TODOS); - } - - void get(ServerRequest req, ServerResponse res) { - res.send(TODO); - } - - void echo(ServerRequest req, ServerResponse res) { - req.content().as(JsonObject.class) - .onError(res::send) - .forSingle(res::send); - } - } - - @BeforeAll - public static void init() { - serverBackend = WebServer.builder() - .addRouting(Routing.builder() - .register("/api/backend", new BackendServiceMock())) - .addMediaSupport(JsonpSupport.create()) - .build() - .start() - .await(Duration.ofMinutes(1)); - - Config config = Config.builder() - .sources(List.of( - classpath("application-test.yaml"), - ConfigSources.create(Map.of("services.backend.endpoint", "http://127.0.0.1:" + serverBackend.port())))) - .build(); - - Security security = Security.create(config.get("security")); - - serverFrontend = WebServer.builder() - .addRouting(Routing.builder() - .register(WebSecurity.create(security, config.get("security"))) - .register("/api", new TodoService(new BackendServiceClient(config)))) - .config(config.get("webserver")) - .addMediaSupport(JsonpSupport.create()) - .build() - .start() - .await(Duration.ofMinutes(1)); - - client = WebClient.builder() - .baseUri("http://localhost:" + serverFrontend.port()) - .addMediaSupport(JsonpSupport.create()) - .useSystemServiceLoader(false) - .addService(WebClientSecurity.create(security)) - .addHeader(Http.Header.AUTHORIZATION, "Basic " + ENCODED_ID) - .build(); - } - - @AfterAll - public static void stopServers() { - if (serverBackend != null) { - serverBackend.shutdown(); - } - if (serverFrontend != null) { - serverFrontend.shutdown(); - } - } - - @Test - public void testList() { - WebClientResponse response = client.get() - .path("/api/todo") - .request() - .await(); - assertThat(response.status(), is(Http.Status.OK_200)); - JsonArray jsonValues = response.content().as(JsonArray.class).await(); - assertThat(jsonValues.getJsonObject(0), is(TODO)); - } - - @Test - public void testCreate() { - WebClientResponse response = client.post() - .path("/api/todo") - .submit(TODO) - .await(); - assertThat(response.status(), is(Http.Status.CREATED_201)); - JsonObject jsonObject = response.content().as(JsonObject.class).await(); - assertThat(jsonObject, is(TODO)); - } - - @Test - public void testGet() { - WebClientResponse response = client.get() - .path("/api/todo/1") - .request() - .await(); - - assertThat(response.status(), is(Http.Status.OK_200)); - JsonObject jsonObject = response.content().as(JsonObject.class).await(); - assertThat(jsonObject, is(TODO)); - } - - @Test - public void testDelete() { - WebClientResponse response = client.delete() - .path("/api/todo/1") - .request() - .await(); - - assertThat(response.status(), is(Http.Status.OK_200)); - JsonObject jsonObject = response.content().as(JsonObject.class).await(); - assertThat(jsonObject, is(TODO)); - } - - @Test - public void testUpdate() { - WebClientResponse response = client.put() - .path("/api/todo/1") - .submit(TODO) - .await(); - - assertThat(response.status(), is(Http.Status.OK_200)); - JsonObject jsonObject = response.content().as(JsonObject.class).await(); - assertThat(jsonObject, is(TODO)); - } -} diff --git a/examples/todo-app/frontend/src/test/resources/application-test.yaml b/examples/todo-app/frontend/src/test/resources/application-test.yaml deleted file mode 100644 index 0e363e78dad..00000000000 --- a/examples/todo-app/frontend/src/test/resources/application-test.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2021, 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -webserver: - port: 0 - -security: - providers: - - http-basic-auth: - realm: "helidon" - users: - - login: "john" - password: "password" - web-server: - paths: - - path: "/api/{+}" - authenticate: true diff --git a/examples/todo-app/pom.xml b/examples/todo-app/pom.xml deleted file mode 100644 index 3462d26f71a..00000000000 --- a/examples/todo-app/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - - io.helidon.examples.todos - example-todo-app-project - pom - 3.2.7-SNAPSHOT - Helidon Examples TODO Demo - - - TODO demo application - - - - frontend - backend - - diff --git a/examples/translator-app/README.md b/examples/translator-app/README.md deleted file mode 100644 index 1a5f18afdbf..00000000000 --- a/examples/translator-app/README.md +++ /dev/null @@ -1,86 +0,0 @@ -# Translator Example Application - -This application demonstrates a pseudo application composed of two microservices - implemented with Helidon SE. - -## Start Zipkin - -With Docker: -```bash -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -``` - -With Java 8+: -```bash -curl -sSL https://zipkin.io/quickstart.sh | bash -s -java -jar zipkin.jar -``` - -With Kubernetes: -```bash -kubectl apply \ - -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/ingress-nginx-3.15.2/deploy/static/provider/cloud/deploy.yaml \ - -f ../k8s/zipkin.yaml -``` - -## Build and run - -With Docker: -```bash -docker build -t helidon-examples-translator-backend backend/ -docker build -t helidon-examples--translator-frontend frontend/ -docker run --rm -d -p 9080:9080 \ - --link zipkin \ - --name helidon-examples-translator-backend \ - helidon-examples-translator-backend:latest -docker run --rm -d -p 8080:8080 \ - --link zipkin \ - --link helidon-examples-translator-backend \ - --name helidon-examples-translator-frontend \ - helidon-examples-translator-frontend:latest -``` - -With Java 8+: -```bash -mvn package -java -jar backend/target/helidon-examples-translator-backend.jar & -java -jar frontend/target/helidon-examples-translator-frontend.jar -``` - -Try the endpoint: -```bash -curl "http://localhost:8080?q=cloud&lang=czech" -curl "http://localhost:8080?q=cloud&lang=french" -curl "http://localhost:8080?q=cloud&lang=italian" -``` - -Then check out the traces at http://localhost:9411. - -## Run with Kubernetes (docker for desktop) - -```bash -docker build -t helidon-examples-translator-backend backend/ -docker build -t helidon-examples-translator-frontend frontend/ -kubectl apply -f backend/app.yaml -f frontend/app.yaml -``` - -Try the endpoint: -```bash -curl "http://localhost/translator?q=cloud&lang=czech" -curl "http://localhost/translator?q=cloud&lang=french" -curl "http://localhost/translator?q=cloud&lang=italian" -``` - -Then check out the traces at http://localhost/zipkin. - -Stop the docker containers: -```bash -docker stop zipkin \ - helidon-examples-translator-backend \ - helidon-examples-translator-frontend -``` - -Delete the Kubernetes resources: -```bash -kubectl delete -f backend/app.yaml -f frontend/app.yaml -``` \ No newline at end of file diff --git a/examples/translator-app/backend/Dockerfile b/examples/translator-app/backend/Dockerfile deleted file mode 100644 index fd93dab3215..00000000000 --- a/examples/translator-app/backend/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-translator-backend.jar ./ -COPY --from=build /helidon/target/libs ./libs - -ENV tracing.host="zipkin" - -CMD ["java", "-jar", "helidon-examples-translator-backend.jar"] - -EXPOSE 9080 diff --git a/examples/translator-app/backend/app.yaml b/examples/translator-app/backend/app.yaml deleted file mode 100644 index 8b5b06b3389..00000000000 --- a/examples/translator-app/backend/app.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-examples-translator-backend - labels: - app: helidon-examples-translator-backend -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-translator-backend - spec: - containers: - - name: helidon-examples-translator-backend - image: helidon-examples-translator-backend:latest - imagePullPolicy: IfNotPresent - ports: - - containerPort: 9080 - env: - - name: tracing.host - value: zipkin ---- - -apiVersion: v1 -kind: Service -metadata: - name: helidon-examples-translator-backend - labels: - app: helidon-examples-translator-backend -spec: - type: ClusterIP - selector: - app: helidon-examples-translator-backend - ports: - - port: 9080 - targetPort: 9080 - name: http diff --git a/examples/translator-app/backend/pom.xml b/examples/translator-app/backend/pom.xml deleted file mode 100644 index 66235a3fb43..00000000000 --- a/examples/translator-app/backend/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.translator - helidon-examples-translator-backend - 3.2.7-SNAPSHOT - Helidon Examples Translator Backend - - - A translator backend example app. - - - - io.helidon.examples.translator.backend.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.tracing - helidon-tracing-zipkin - - - io.helidon.config - helidon-config - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/Main.java b/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/Main.java deleted file mode 100644 index 6c771947d6a..00000000000 --- a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/Main.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.translator.backend; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Translator application backend main class. - */ -public class Main { - - private Main() { - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - public static Single startBackendServer() { - // configure logging in order to not have the standard JVM defaults - LogConfig.configureRuntime(); - - Config config = Config.builder() - .sources(ConfigSources.environmentVariables()) - .build(); - - WebServer webServer = WebServer.builder( - Routing.builder() - .register(new TranslatorBackendService())) - .port(9080) - .tracer(TracerBuilder.create(config.get("tracing")) - .serviceName("helidon-webserver-translator-backend") - .build()) - .build(); - - return webServer.start() - .peek(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port()); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }).onError(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - } - - /** - * The main method of Translator backend. - * - * @param args command-line args, currently ignored. - */ - public static void main(String[] args) { - startBackendServer(); - } -} diff --git a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/TranslatorBackendService.java b/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/TranslatorBackendService.java deleted file mode 100644 index 929f48807b3..00000000000 --- a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/TranslatorBackendService.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.translator.backend; - -import java.util.HashMap; -import java.util.Map; - -import io.helidon.webserver.BadRequestException; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * Translator backend service. - */ -public class TranslatorBackendService implements Service { - - private static final String CZECH = "czech"; - private static final String SPANISH = "spanish"; - private static final String CHINESE = "chinese"; - private static final String HINDI = "hindi"; - private static final String ITALIAN = "italian"; - private static final String FRENCH = "french"; - - private static final String SEPARATOR = "."; - private static final Map TRANSLATED_WORDS_REPOSITORY = new HashMap<>(); - - static { - //translation for word "cloud" - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + CZECH, "oblak"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + SPANISH, "nube"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + CHINESE, "云"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + HINDI, "बादल"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + ITALIAN, "nube"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + FRENCH, "nuage"); - - //one two three four five six seven eight nine ten - //jedna dvě tři čtyři pět šest sedm osm devět deset - //uno dos tres cuatro cinco seis siete ocho nueve diez - //一二三四五六七八九十 - //एक दो तीन चार पांच छ सात आठ नौ दस - // uno due tre quattro cinque sei sette otto nove dieci - // un deux trois quatre cinq six sept huit neuf dix - - //translation for word "one" - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + CZECH, "jedna"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + SPANISH, "uno"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + CHINESE, "一"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + HINDI, "एक"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + ITALIAN, "uno"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + FRENCH, "un"); - //translation for word "two" - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + CZECH, "dvě"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + SPANISH, "dos"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + CHINESE, "二"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + HINDI, "दो"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + ITALIAN, "due"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + FRENCH, "deux"); - //translation for word "three" - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + CZECH, "tři"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + SPANISH, "tres"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + CHINESE, "三"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + HINDI, "तीन"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + ITALIAN, "tre"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + FRENCH, "trois"); - //translation for word "four" - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + CZECH, "čtyři"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + SPANISH, "cuatro"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + CHINESE, "四"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + HINDI, "चार"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + ITALIAN, "quattro"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + FRENCH, "quatre"); - //translation for word "five" - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + CZECH, "pět"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + SPANISH, "cinco"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + CHINESE, "五"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + HINDI, "पांच"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + ITALIAN, "cinque"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + FRENCH, "cinq"); - //translation for word "six" - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + CZECH, "šest"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + SPANISH, "seis"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + CHINESE, "六"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + HINDI, "छ"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + ITALIAN, "sei"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + FRENCH, "six"); - //translation for word "seven" - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + CZECH, "sedm"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + SPANISH, "siete"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + CHINESE, "七"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + HINDI, "सात"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + ITALIAN, "sette"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + FRENCH, "sept"); - //translation for word "eight" - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + CZECH, "osm"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + SPANISH, "ocho"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + CHINESE, "八"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + HINDI, "आठ"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + ITALIAN, "otto"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + FRENCH, "huit"); - //translation for word "nine" - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + CZECH, "devět"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + SPANISH, "nueve"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + CHINESE, "九"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + HINDI, "नौ"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + ITALIAN, "nove"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + FRENCH, "neuf"); - //translation for word "ten" - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + CZECH, "deset"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + SPANISH, "diez"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + CHINESE, "十"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + HINDI, "दस"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + ITALIAN, "dieci"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + FRENCH, "dix"); - } - - @Override - public void update(Routing.Rules rules) { - rules.get(this::getText); - } - - private void getText(ServerRequest request, ServerResponse response) { - - String query = request.queryParams().first("q") - .orElseThrow(() -> new BadRequestException("missing query parameter 'q'")); - String language = request.queryParams().first("lang") - .orElseThrow(() -> new BadRequestException("missing query parameter 'lang'")); - String translation; - switch (language) { - case CZECH: - translation = TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + CZECH); - break; - case SPANISH: - translation = TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + SPANISH); - break; - case CHINESE: - translation = TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + CHINESE); - break; - case HINDI: - translation = TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + HINDI); - break; - case ITALIAN: - translation = TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + ITALIAN); - break; - case FRENCH: - translation = TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + FRENCH); - break; - default: - response.status(404) - .send(String.format( - "Language '%s' not in supported. Supported languages: %s, %s, %s, %s.", - language, - CZECH, SPANISH, CHINESE, HINDI)); - return; - } - - if (translation != null) { - response.send(translation); - } else { - response.status(404) - .send(String.format("Word '%s' not in the dictionary", query)); - } - } -} diff --git a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/package-info.java b/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/package-info.java deleted file mode 100644 index b73bbaa5690..00000000000 --- a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Demo examples Translator Backend package. - */ -package io.helidon.examples.translator.backend; diff --git a/examples/translator-app/backend/src/main/resources/logging.properties b/examples/translator-app/backend/src/main/resources/logging.properties deleted file mode 100644 index b83e3834510..00000000000 --- a/examples/translator-app/backend/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -#All attributes details -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#All log level details -.level=INFO - -io.helidon.webserver.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/translator-app/frontend/Dockerfile b/examples/translator-app/frontend/Dockerfile deleted file mode 100644 index c539e9f9469..00000000000 --- a/examples/translator-app/frontend/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Dmaven.test.skip - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-translator-frontend.jar ./ -COPY --from=build /helidon/target/libs ./libs - -ENV tracing.host="zipkin" -ENV backend.host="helidon-examples-translator-backend" - -CMD ["java", "-jar", "helidon-examples-translator-frontend.jar"] - -EXPOSE 8080 diff --git a/examples/translator-app/frontend/app.yaml b/examples/translator-app/frontend/app.yaml deleted file mode 100644 index c9359dd25b2..00000000000 --- a/examples/translator-app/frontend/app.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-examples-translator-frontend - labels: - app: helidon-examples-translator-frontend -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-translator-frontend - spec: - containers: - - name: translator-frontend - image: helidon-examples-translator-frontend:latest - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 - env: - - name: tracing.host - value: zipkin - - name: backend.host - value: helidon-examples-translator-backend - ---- - -apiVersion: v1 -kind: Service -metadata: - name: helidon-examples-translator-frontend - labels: - app: helidon-examples-translator-frontend -spec: - type: ClusterIP - ports: - - name: http - port: 8080 - selector: - app: helidon-examples-translator-frontend - sessionAffinity: None - ---- - -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: helidon-examples-translator-frontend -spec: - rules: - - host: localhost - http: - paths: - - path: /translator - pathType: Prefix - backend: - service: - name: helidon-examples-translator-frontend - port: - number: 8080 diff --git a/examples/translator-app/frontend/pom.xml b/examples/translator-app/frontend/pom.xml deleted file mode 100644 index 3d4a551acc7..00000000000 --- a/examples/translator-app/frontend/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.translator - helidon-examples-translator-frontend - 3.2.7-SNAPSHOT - Helidon Examples Translator Frontend - - - A translator frontend example app. - - - - io.helidon.examples.translator.frontend.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config - - - io.helidon.tracing - helidon-tracing-jersey-client - - - io.helidon.tracing - helidon-tracing-zipkin - - - io.helidon.common - helidon-common - - - jakarta.inject - jakarta.inject-api - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - - - add-backend-dependency - - - !maven.test.skip - - - - - io.helidon.examples.translator - helidon-examples-translator-backend - ${project.version} - test - - - - - diff --git a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/Main.java b/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/Main.java deleted file mode 100644 index 51ee07d36d3..00000000000 --- a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/Main.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.translator.frontend; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Translator application frontend main class. - */ -public class Main { - - private Main() { - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - public static Single startFrontendServer() { - // configure logging in order to not have the standard JVM defaults - LogConfig.configureRuntime(); - - Config config = Config.builder() - .sources(ConfigSources.environmentVariables()) - .build(); - - WebServer webServer = WebServer.builder( - Routing.builder() - .register(new TranslatorFrontendService( - config.get("backend.host").asString().orElse("localhost"), - 9080))) - .port(8080) - .tracer(TracerBuilder.create(config.get("tracing")) - .serviceName("helidon-webserver-translator-frontend") - .registerGlobal(false) - .build()) - .build(); - - return webServer.start() - .peek(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port()); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }).onError(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - } - - /** - * The main method of Translator frontend. - * - * @param args command-line args, currently ignored. - */ - public static void main(String[] args) { - startFrontendServer(); - } -} diff --git a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/TranslatorFrontendService.java b/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/TranslatorFrontendService.java deleted file mode 100644 index 805eb387fa4..00000000000 --- a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/TranslatorFrontendService.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.translator.frontend; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.tracing.jersey.client.ClientTracingFilter; -import io.helidon.webserver.BadRequestException; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.ws.rs.ProcessingException; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; - -/** - * Translator frontend resource. - */ -public final class TranslatorFrontendService implements Service { - - private static final Logger LOGGER = Logger.getLogger(TranslatorFrontendService.class.getName()); - private final WebTarget backendTarget; - - TranslatorFrontendService(String backendHostname, int backendPort) { - backendTarget = ClientBuilder.newClient() - .target("http://" + backendHostname + ":" + backendPort); - } - - @Override - public void update(Routing.Rules rules) { - rules.get(this::getText); - } - - private void getText(ServerRequest request, ServerResponse response) { - try { - String query = request.queryParams().first("q") - .orElseThrow(() -> new BadRequestException("missing query parameter 'q'")); - String language = request.queryParams().first("lang") - .orElseThrow(() -> new BadRequestException("missing query parameter 'lang'")); - - try (Response backendResponse = backendTarget - .property(ClientTracingFilter.TRACER_PROPERTY_NAME, request.tracer()) - .property(ClientTracingFilter.CURRENT_SPAN_CONTEXT_PROPERTY_NAME, request.spanContext().orElse(null)) - .queryParam("q", query) - .queryParam("lang", language) - .request() - .get()) { - final String result; - if (backendResponse.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) { - result = backendResponse.readEntity(String.class); - } else { - result = "Error: " + backendResponse.readEntity(String.class); - } - response.send(result + "\n"); - } - } catch (ProcessingException pe) { - LOGGER.log(Level.WARNING, "Problem to call translator frontend.", pe); - response.status(503).send("Translator backend service isn't available."); - } - } -} diff --git a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/package-info.java b/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/package-info.java deleted file mode 100644 index 4729f81fc50..00000000000 --- a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Demo examples Translator Frontend package. - */ -package io.helidon.examples.translator.frontend; diff --git a/examples/translator-app/frontend/src/main/resources/logging.properties b/examples/translator-app/frontend/src/main/resources/logging.properties deleted file mode 100644 index b83e3834510..00000000000 --- a/examples/translator-app/frontend/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -#All attributes details -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#All log level details -.level=INFO - -io.helidon.webserver.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/translator-app/frontend/src/test/java/io/helidon/examples/translator/TranslatorTest.java b/examples/translator-app/frontend/src/test/java/io/helidon/examples/translator/TranslatorTest.java deleted file mode 100644 index 4a2ce5550fd..00000000000 --- a/examples/translator-app/frontend/src/test/java/io/helidon/examples/translator/TranslatorTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.translator; - -import java.util.concurrent.TimeUnit; - -import io.helidon.webserver.WebServer; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.examples.translator.backend.Main.startBackendServer; -import static io.helidon.examples.translator.frontend.Main.startFrontendServer; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * The TranslatorTest. - */ -public class TranslatorTest { - - private static WebServer webServerFrontend; - private static WebServer webServerBackend; - private static Client client; - private static WebTarget target; - - @BeforeAll - public static void setUp() { - webServerBackend = startBackendServer().await(10, TimeUnit.SECONDS); - webServerFrontend = startFrontendServer().await(10, TimeUnit.SECONDS); - client = ClientBuilder.newClient(); - target = client.target("http://localhost:" + webServerFrontend.port()); - } - - @AfterAll - public static void tearDown() { - webServerFrontend.shutdown().await(10, TimeUnit.SECONDS); - webServerBackend.shutdown().await(10, TimeUnit.SECONDS); - if (client != null) { - client.close(); - } - } - - @Test - public void testCzech() { - try (Response response = target.queryParam("q", "cloud") - .queryParam("lang", "czech") - .request() - .get()) { - assertThat("Unexpected response! Status code: " + response.getStatus(), - response.readEntity(String.class), is("oblak\n")); - } - } - - @Test - public void testItalian() { - try (Response response = target.queryParam("q", "cloud") - .queryParam("lang", "italian") - .request() - .get()) { - assertThat("Unexpected response! Status code: " + response.getStatus(), - response.readEntity(String.class), is("nube\n")); - } - } - - @Test - public void testFrench() { - try (Response response = target.queryParam("q", "cloud") - .queryParam("lang", "french") - .request() - .get()) { - assertThat("Unexpected response! Status code: " + response.getStatus(), - response.readEntity(String.class), is("nuage\n")); - } - } -} diff --git a/examples/translator-app/pom.xml b/examples/translator-app/pom.xml deleted file mode 100644 index 4c9c3d5c2c2..00000000000 --- a/examples/translator-app/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.translator - helidon-examples-translator-project - pom - Helidon Examples Translator Demo - - - A translator example app. - - - - backend - frontend - - diff --git a/examples/webclient/pom.xml b/examples/webclient/pom.xml deleted file mode 100644 index bd5025b4086..00000000000 --- a/examples/webclient/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - - io.helidon.examples.webclient - helidon-examples-webclient-project - Helidon WebClient Example - - pom - - - standalone - - diff --git a/examples/webclient/standalone/README.md b/examples/webclient/standalone/README.md deleted file mode 100644 index 15322eb76c4..00000000000 --- a/examples/webclient/standalone/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Standalone WebClient Example - -This example demonstrates how to use the Helidon SE WebClient from a -standalone Java program to connect to a server. - -## Build - -``` -mvn package -``` - -## Run - -First, start the server: - -``` -java -jar target/helidon-examples-webclient-standalone.jar -``` - -Note the port number that it displays. For example: - -``` -WEB server is up! http://localhost:PORT/greet -``` - -Then run the client, passing the port number. It will connect -to the server: - -``` -java -cp "target/classes:target/libs/*" io.helidon.examples.webclient.standalone.ClientMain PORT -``` - diff --git a/examples/webclient/standalone/pom.xml b/examples/webclient/standalone/pom.xml deleted file mode 100644 index 499738d63f8..00000000000 --- a/examples/webclient/standalone/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - 4.0.0 - - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-webclient-standalone - Helidon WebClient Standalone Example - - - io.helidon.examples.webclient.standalone.ServerMain - - - - - io.helidon.bundles - helidon-bundles-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-metrics - - - io.helidon.metrics - helidon-metrics - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ClientMain.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ClientMain.java deleted file mode 100644 index 72283b6e7df..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ClientMain.java +++ /dev/null @@ -1,198 +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. - */ -package io.helidon.examples.webclient.standalone; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; - -import io.helidon.common.http.DataChunk; -import io.helidon.common.http.Http; -import io.helidon.common.reactive.IoMulti; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.config.ConfigValue; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webclient.metrics.WebClientMetrics; -import io.helidon.webclient.spi.WebClientService; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricRegistry; - -/** - * A simple WebClient usage class. - * - * Each of the methods demonstrates different usage of the WebClient. - */ -public class ClientMain { - - private static final MetricRegistry METRIC_REGISTRY = RegistryFactory.getInstance() - .getRegistry(MetricRegistry.Type.APPLICATION); - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject JSON_NEW_GREETING; - - static { - JSON_NEW_GREETING = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - private ClientMain() { - } - - /** - * Executes WebClient examples. - * - * If no argument provided it will take server port from configuration server.port. - * - * User can override port from configuration by main method parameter with the specific port. - * - * @param args main method - */ - public static void main(String[] args) { - Config config = Config.create(); - String url; - if (args.length == 0) { - ConfigValue port = config.get("server.port").asInt(); - if (!port.isPresent() || port.get() == -1) { - throw new IllegalStateException("Unknown port! Please specify port as a main method parameter " - + "or directly to config server.port"); - } - url = "http://localhost:" + port.get() + "/greet"; - } else { - url = "http://localhost:" + Integer.parseInt(args[0]) + "/greet"; - } - - WebClient webClient = WebClient.builder() - .baseUri(url) - .config(config.get("client")) - //Since JSON processing support is not present by default, we have to add it. - .addMediaSupport(JsonpSupport.create()) - .build(); - - performPutMethod(webClient) - .flatMapSingle(it -> performGetMethod(webClient)) - .flatMapSingle(it -> followRedirects(webClient)) - .flatMapSingle(it -> getResponseAsAnJsonObject(webClient)) - .flatMapSingle(it -> saveResponseToFile(webClient)) - .flatMapSingle(it -> clientMetricsExample(url, config)) - //Now we need to wait until all requests are done. - .await(); - } - - static Single performPutMethod(WebClient webClient) { - System.out.println("Put request execution."); - return webClient.put() - .path("/greeting") - .submit(JSON_NEW_GREETING) - .map(WebClientResponse::status) - .peek(status -> System.out.println("PUT request executed with status: " + status)); - } - - static Single performGetMethod(WebClient webClient) { - System.out.println("Get request execution."); - return webClient.get() - .request(String.class) - .peek(string -> { - System.out.println("GET request successfully executed."); - System.out.println(string); - }); - } - - static Single followRedirects(WebClient webClient) { - System.out.println("Following request redirection."); - return webClient.get() - .path("/redirect") - .request() - .flatMapSingle(response -> { - if (response.status() != Http.Status.OK_200) { - throw new IllegalStateException("Follow redirection failed!"); - } - return response.content().as(String.class); - }) - .peek(string -> { - System.out.println("Redirected request successfully followed."); - System.out.println(string); - }); - } - - static Single getResponseAsAnJsonObject(WebClient webClient) { - //Support for JsonObject reading from response is not present by default. - //In case of this example it was registered at creation time of the WebClient instance. - System.out.println("Requesting from JsonObject."); - return webClient.get() - .request(JsonObject.class) - .peek(jsonObject -> { - System.out.println("JsonObject successfully obtained."); - System.out.println(jsonObject); - }); - } - - static Single saveResponseToFile(WebClient webClient) { - //We have to create file subscriber first. This subscriber will save the content of the response to the file. - Path file = Paths.get("test.txt"); - try { - Files.deleteIfExists(file); - Files.createFile(file); - } catch (IOException e) { - e.printStackTrace(); - } - - System.out.println("Downloading server response to file: " + file); - return webClient.get() - .request() - .map(WebClientResponse::content) - .flatMapSingle(content -> content - .map(DataChunk::data) - .flatMapIterable(Arrays::asList) - .to(IoMulti.writeToFile(file).build())) - .peek(path -> System.out.println("Download complete!")); - } - - static Single clientMetricsExample(String url, Config config) { - //This part here is only for verification purposes, it is not needed to be done for actual usage. - String counterName = "example.metric.GET.localhost"; - Counter counter = METRIC_REGISTRY.counter(counterName); - System.out.println(counterName + ": " + counter.getCount()); - - //Creates new metric which will count all GET requests and has format of example.metric.GET. - WebClientService clientService = WebClientMetrics.counter() - .methods(Http.Method.GET) - .nameFormat("example.metric.%1$s.%2$s") - .build(); - - //This newly created metric now needs to be registered to WebClient. - WebClient webClient = WebClient.builder() - .baseUri(url) - .config(config) - .addService(clientService) - .build(); - - //Perform any GET request using this newly created WebClient instance. - return performGetMethod(webClient) - //Verification for example purposes that metric has been incremented. - .peek(s -> System.out.println(counterName + ": " + counter.getCount())); - } -} diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/GreetService.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/GreetService.java deleted file mode 100644 index 4a1ab348dbb..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/GreetService.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.examples.webclient.standalone; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - GreetService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/redirect", this::redirect) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, - ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a status code of {@link Http.Status#MOVED_PERMANENTLY_301} and the new location where should - * client redirect. - * - * @param request the server request - * @param response the server response - */ - private void redirect(ServerRequest request, - ServerResponse response) { - response.headers().add(Http.Header.LOCATION, "http://localhost:" + ServerMain.getServerPort() + "/greet/"); - response.status(Http.Status.MOVED_PERMANENTLY_301).send(); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, - ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - /** - * Set the greeting to use in future messages. - * - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - if (ex.getCause() instanceof JsonException) { - - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } -} diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ServerMain.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ServerMain.java deleted file mode 100644 index f8b09e7c8ff..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ServerMain.java +++ /dev/null @@ -1,98 +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. - */ -package io.helidon.examples.webclient.standalone; - -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class ServerMain { - - private static int serverPort = -1; - - /** - * Cannot be instantiated. - */ - private ServerMain() { - } - - /** - * WebServer starting method. - * - * @param args starting arguments - */ - public static void main(String[] args) { - startServer(); - } - - /** - * Returns current port of the running server. - * - * @return server port - */ - public static int getServerPort() { - return serverPort; - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - */ - static Single startServer() { - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - - WebServer server = WebServer.builder(createRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - // Server threads are not daemon. No need to block. Just react. - return server.start() - .peek(ws -> { - serverPort = ws.port(); - System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }).onError(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - } - - /** - * Creates new {@link Routing}. - * - * @param config configuration of this server - * @return routing configured with JSON support, a health check, and a service - */ - private static Routing createRouting(Config config) { - MetricsSupport metrics = MetricsSupport.create(); - GreetService greetService = new GreetService(config); - return Routing.builder() - .register(metrics) - .register("/greet", greetService) - .build(); - } -} diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/package-info.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/package-info.java deleted file mode 100644 index 9cfd5eb785b..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Basic examples of webclient usage. - */ -package io.helidon.examples.webclient.standalone; diff --git a/examples/webclient/standalone/src/main/resources/application.yaml b/examples/webclient/standalone/src/main/resources/application.yaml deleted file mode 100644 index 657b26fe54d..00000000000 --- a/examples/webclient/standalone/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -app: - greeting: "Hello" - -server: - port: -1 - host: 0.0.0.0 - -client: - follow-redirects: true - max-redirects: 8 \ No newline at end of file diff --git a/examples/webclient/standalone/src/main/resources/full-webclient-config.yaml b/examples/webclient/standalone/src/main/resources/full-webclient-config.yaml deleted file mode 100644 index 7eabb560ca4..00000000000 --- a/examples/webclient/standalone/src/main/resources/full-webclient-config.yaml +++ /dev/null @@ -1,75 +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. -# -client: - event-loop: - name-prefix: client-thread- - workers: 1 - connect-timeout-millis: 2000 - read-timeout-millis: 2000 - follow-redirects: true - max-redirects: 5 - user-agent: "Helidon" - cookies: - automatic-store-enabled: true - default-cookies: - - name: "env" - value: "dev" - headers: - - name: "Accept" - value: ["application/json","text/plain"] - services: - exclude: ["some.webclient.service.Provider"] - config: - metrics: - - type: METER - name-format: "client.meter.overall" - - type: TIMER - # meter per method - name-format: "client.meter.%1$s" - - methods: ["GET"] - type: COUNTER - errors: false - name-format: "client.counter.%1$s.success" - description: "Counter of successful GET requests" - - methods: ["PUT", "POST", "DELETE"] - type: COUNTER - success: false - name-format: "wc.counter.%1$s.error" - description: "Counter of failed PUT, POST and DELETE requests" - - methods: ["GET"] - type: GAUGE_IN_PROGRESS - name-format: "client.inprogress.%2$s" - description: "In progress requests to host" - tracing: - proxy: - use-system-selector: false - host: "hostName" - port: 80 - no-proxy: ["localhost:8080", ".helidon.io", "192.168.1.1"] - ssl: - server: - disable-hostname-verification: false - trust-all: false - truststore: - keystore-resource-path: "path to the keystore" - keystore-type: "JKS" - keystore-passphrase: "password" - trust-store: true - client: - keystore: - keystore-resource-path: "path to client keystore" - keystore-passphrase: "password" - trust-store: true diff --git a/examples/webclient/standalone/src/test/java/io/helidon/examples/webclient/standalone/ClientMainTest.java b/examples/webclient/standalone/src/test/java/io/helidon/examples/webclient/standalone/ClientMainTest.java deleted file mode 100644 index 0f75430beaf..00000000000 --- a/examples/webclient/standalone/src/test/java/io/helidon/examples/webclient/standalone/ClientMainTest.java +++ /dev/null @@ -1,147 +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. - */ -package io.helidon.examples.webclient.standalone; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import io.helidon.common.http.Http; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.api.RegistryFactory; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientRequestBuilder; -import io.helidon.webclient.WebClientServiceRequest; -import io.helidon.webclient.WebClientServiceResponse; -import io.helidon.webclient.spi.WebClientService; -import io.helidon.webserver.WebServer; - -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Test for verification of WebClient example. - */ -public class ClientMainTest { - - private static final MetricRegistry METRIC_REGISTRY = RegistryFactory.getInstance() - .getRegistry(MetricRegistry.Type.APPLICATION); - - private WebClient webClient; - private Path testFile; - - @BeforeEach - public void beforeEach() { - testFile = Paths.get("test.txt"); - WebServer server = ServerMain.startServer().await(); - createWebClient(server.port()); - } - - @AfterEach - public void afterEach() throws IOException { - Files.deleteIfExists(testFile); - } - - private void createWebClient(int port, WebClientService... services) { - Config config = Config.create(); - WebClient.Builder builder = WebClient.builder() - .baseUri("http://localhost:" + port + "/greet") - .config(config.get("client")) - .addMediaSupport(JsonpSupport.create()); - for (WebClientService service : services) { - builder.addService(service); - } - webClient = builder.build(); - } - - @Test - public void testPerformPutAndGetMethod() { - ClientMain.performGetMethod(webClient) - .thenAccept(it -> assertThat(it, is("{\"message\":\"Hello World!\"}"))) - .thenCompose(it -> ClientMain.performPutMethod(webClient)) - .thenCompose(it -> ClientMain.performGetMethod(webClient)) - .thenAccept(it -> assertThat(it, is("{\"message\":\"Hola World!\"}"))) - .await(); - } - - @Test - public void testPerformRedirect() { - createWebClient(ServerMain.getServerPort(), new RedirectClientServiceTest()); - ClientMain.followRedirects(webClient) - .thenAccept(it -> assertThat(it, is("{\"message\":\"Hello World!\"}"))) - .await(); - } - - @Test - public void testFileDownload() { - ClientMain.saveResponseToFile(webClient) - .thenAccept(it -> assertThat(Files.exists(testFile), is(true))) - .thenAccept(it -> { - try { - assertThat(Files.readString(testFile), is("{\"message\":\"Hello World!\"}")); - } catch (IOException e) { - fail(e); - } - }) - .await(); - } - - @Test - public void testMetricsExample() { - String counterName = "example.metric.GET.localhost"; - Counter counter = METRIC_REGISTRY.counter(counterName); - assertThat("Counter " + counterName + " has not been 0", counter.getCount(), is(0L)); - ClientMain.clientMetricsExample("http://localhost:" + ServerMain.getServerPort() + "/greet", Config.create()) - .thenAccept(it -> assertThat("Counter " + counterName + " " - + "has not been 1", counter.getCount(), is(1L))) - .await(); - } - - private static final class RedirectClientServiceTest implements WebClientService { - - private volatile boolean redirect = true; - - @Override - public Single response(WebClientRequestBuilder.ClientRequest request, - WebClientServiceResponse response) { - - if (response.status() == Http.Status.MOVED_PERMANENTLY_301 && redirect) { - fail("Received second redirect! Only one redirect expected here."); - } else if (response.status() == Http.Status.OK_200 && !redirect) { - fail("There was status 200 without status 301 before it."); - } - // not used for now, this test must be refactored - //redirect = !redirect; - return Single.just(response); - } - - @Override - public Single request(WebClientServiceRequest request) { - return Single.just(request); - } - } - -} diff --git a/examples/webserver/README.md b/examples/webserver/README.md deleted file mode 100644 index 41c29e619fe..00000000000 --- a/examples/webserver/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Helidon SE WebServer Examples - -This directory contains Helidon SE webserver examples. \ No newline at end of file diff --git a/examples/webserver/basics/README.md b/examples/webserver/basics/README.md deleted file mode 100644 index 07997b01fa4..00000000000 --- a/examples/webserver/basics/README.md +++ /dev/null @@ -1,45 +0,0 @@ - -# Helidon WebServer Basic Example - -This example consists of various methods that can be selected -at runtime. Each method illustrates a different WebServer concept. -See the comments in `Main.java` for a description of the various -methods. - -## Build and run - -```bash -mvn package -``` - -To see the list of methods that are available run: - -```bash -java -DexampleName=help -jar target/helidon-examples-webserver-basics.jar -``` - -You should see output like: - -``` -Example method names: - help - h - firstRouting - startServer - routingAsFilter - parametersAndHeaders - advancedRouting - organiseCode - readContentEntity - filterAndProcessEntity - supports - errorHandling -``` - -You can then choose the method to execute by setting the `exampleName` system property: - -``` -java -DexampleName=firstRouting -jar target/helidon-examples-webserver-basics.jar -``` - -This will start the Helidon SE WebServer using the method indicated. diff --git a/examples/webserver/basics/pom.xml b/examples/webserver/basics/pom.xml deleted file mode 100644 index 9c5b569f9a5..00000000000 --- a/examples/webserver/basics/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-basics - Helidon WebServer Examples Basics - - - Examples of elementary use of the Web Server - - - - io.helidon.webserver.examples.basics.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver - helidon-webserver-jersey - - - io.helidon.media - helidon-media-jsonp - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Catalog.java b/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Catalog.java deleted file mode 100644 index fd1830a4d1d..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Catalog.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.basics; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * Skeleton example of catalog resource use in {@link Main} class. - */ -public class Catalog implements Service { - - @Override - public void update(Routing.Rules rules) { - rules.get("/", this::list) - .get("/{id}", (req, res) -> getSingle(res, req.path().param("id"))); - } - - private void list(ServerRequest request, ServerResponse response) { - response.send("1, 2, 3, 4, 5"); - } - - private void getSingle(ServerResponse response, String id) { - response.send("Item: " + id); - } -} diff --git a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/HelloWorldResource.java b/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/HelloWorldResource.java deleted file mode 100644 index 626329c1303..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/HelloWorldResource.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.basics; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * Example of the JAX-RS resource. It is integrated with WebServer in {@link Main} class example. - */ -@Path("hw") -public class HelloWorldResource { - - /** - * Jest returns Hello world!. - * - * @return 'Hello world!' literal - */ - @GET - public String helloWorld() { - return "Hello world!"; - } -} diff --git a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Main.java b/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Main.java deleted file mode 100644 index 335404ff241..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Main.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.basics; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Collections; - -import io.helidon.common.http.DataChunk; -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.common.http.Parameters; -import io.helidon.media.common.MediaContext; -import io.helidon.media.common.MessageBodyReader; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webserver.Handler; -import io.helidon.webserver.HttpException; -import io.helidon.webserver.RequestPredicate; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.jersey.JerseySupport; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; - -/** - * This example consists of few first tutorial steps of WebServer API. Each step is represented by a single method. - *

    - * Principles: - *

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

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

    - * The (route) {@link Handler} is a functional interface which process HTTP {@link io.helidon.webserver.ServerRequest request} and - * writes to the {@link io.helidon.webserver.ServerResponse response}. - */ - public void firstRouting() { - Routing routing = Routing.builder() - .post("/post-endpoint", (req, res) -> res.status(Http.Status.CREATED_201) - .send()) - .get("/get-endpoint", (req, res) -> res.status(Http.Status.NO_CONTENT_204) - .send("Hello World!")) - .build(); - startServer(routing); - } - - /** - * {@link Routing} instance can be used to create {@link WebServer} instance. - * It provides a simple, non-blocking life-cycle API returning - * {@link java.util.concurrent.CompletionStage CompletionStages} to provide reactive access. - * - * @param routing the routing to drive by WebServer instance - * @param mediaContext media support - */ - protected void startServer(Routing routing, MediaContext mediaContext) { - WebServer.builder(routing) - .mediaContext(mediaContext) - .build() - .start() - // All lifecycle operations are non-blocking and provides CompletionStage - .whenComplete((ws, thr) -> { - if (thr == null) { - System.out.println("Server is UP: http://localhost:" + ws.port()); - } else { - System.out.println("Can NOT start WebServer!"); - thr.printStackTrace(System.out); - } - }); - } - - /** - * {@link Routing} - * can be used to create {@link WebServer} instance.It provides a simple, non-blocking life-cycle API returning - * {@link java.util.concurrent.CompletionStage CompletionStages} to provide reactive access. - * - * @param routing the routing to drive by WebServer instance - */ - protected void startServer(Routing routing) { - startServer(routing, MediaContext.create()); - } - - /** - * All routing rules (routes) are evaluated in a definition order. The {@link Handler} assigned with the first valid route - * for given request is called. It is a responsibility of each handler to process in one of the following ways: - *

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

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

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

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

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

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

    - * WebServer {@link Parameters Parameters} API is used to represent fact, that headers and - * query parameters can contain multiple values. - */ - public void parametersAndHeaders() { - Routing routing = Routing.builder() - .get("/context/{id}", (req, res) -> { - StringBuilder sb = new StringBuilder(); - // Request headers - req.headers() - .first("foo") - .ifPresent(v -> sb.append("foo: ").append(v).append("\n")); - // Request parameters - req.queryParams() - .first("bar") - .ifPresent(v -> sb.append("bar: ").append(v).append("\n")); - // Path parameters - sb.append("id: ").append(req.path().param("id")); - // Response headers - res.headers().contentType(MediaType.TEXT_PLAIN); - // Response entity (payload) - res.send(sb.toString()); - }) - .build(); - startServer(routing); - } - - /** - * Routing rules (routes) are limited on two criteria - HTTP method and path. {@link RequestPredicate} can be used - * to specify more complex criteria. - */ - public void advancedRouting() { - Routing routing = Routing.builder() - .get("/foo", RequestPredicate.create() - .accepts(MediaType.TEXT_PLAIN) - .containsHeader("bar") - .thenApply((req, res) -> res.send())) - .build(); - startServer(routing); - } - - /** - * Larger applications with many routing rules can cause complicated readability (maintainability) if all rules are - * defined in a single fluent code. It is possible to register {@link io.helidon.webserver.Service Service} and organise - * the code into services and resources. {@code Service} is an interface which can register more routing rules (routes). - */ - public void organiseCode() { - Routing routing = Routing.builder() - .register("/catalog-context-path", new Catalog()) - .build(); - startServer(routing); - } - - /** - * Request payload (body/entity) is represented by {@link java.util.concurrent.Flow.Publisher Flow.Publisher} - * of {@link DataChunk RequestChunks} to enable reactive processing of the content of any size. - * But it is more convenient to process entity in some type specific form. WebServer supports few types which can be - * used te read the whole entity: - *

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

    - * Similar approach is used for the response entity. - */ - public void readContentEntity() { - Routing routing = Routing.builder() - .post("/foo", (req, res) -> { - req.content() - .as(String.class) - // The whole entity can be read when all request chunks are processed - CompletionStage - .whenComplete((data, thr) -> { - if (thr == null) { - System.out.println("/foo DATA: " + data); - res.send(data); - } else { - res.status(Http.Status.BAD_REQUEST_400); - } - }); - }) - // It is possible to use Hanlder.of() method to automatically cover all error states. - .post("/bar", Handler.create(String.class, (req, res, data) -> { - System.out.println("/foo DATA: " + data); - res.send(data); - })) - .build(); - startServer(routing); - } - - /** - * Use a custom {@link MessageBodyReader reader} to convert the request content into an object of a given type. - */ - public void mediaReader() { - Routing routing = Routing.builder() - .post("/create-record", Handler.create(Name.class, (req, res, name) -> { - System.out.println("Name: " + name); - res.status(Http.Status.CREATED_201) - .send(name.toString()); - })) - .build(); - - // Create a media support that contains the defaults and our custom Name reader - MediaContext mediaContext = MediaContext.builder() - .addReader(NameReader.create()) - .build(); - - startServer(routing, mediaContext); - } - - /** - * Combination of filtering {@link Handler} pattern with {@link io.helidon.webserver.Service Service} registration capabilities - * can be used by other frameworks for the integration. WebServer is shipped with several integrated libraries (supports) - * including static content, JSON and Jersey. See {@code POM.xml} for requested dependencies. - */ - public void supports() { - Routing routing = Routing.builder() - .register(StaticContentSupport.create("/static")) - .get("/hello/{what}", (req, res) -> res.send(JSON.createObjectBuilder() - .add("message", - "Hello " + req.path() - .param("what")) - .build())) - .register("/api", JerseySupport.builder() - .register(HelloWorldResource.class) - .build()) - .build(); - - MediaContext mediaContext = MediaContext.builder() - .addWriter(JsonpSupport.writer()) - .build(); - - startServer(routing, mediaContext); - } - - /** - * Request processing can cause error represented by {@link Throwable}. It is possible to register custom - * {@link io.helidon.webserver.ErrorHandler ErrorHandlers} for specific processing. - *

    - * If error is not processed by a custom {@link io.helidon.webserver.ErrorHandler ErrorHandler} than default one is used. - * It respond with HTTP 500 code unless error is not represented - * by {@link HttpException HttpException}. In such case it reflects its content. - */ - public void errorHandling() { - Routing routing = Routing.builder() - .post("/compute", Handler.create(String.class, (req, res, str) -> { - int result = 100 / Integer.parseInt(str); - res.send(String.valueOf("100 / " + str + " = " + result)); - })) - .error(Throwable.class, (req, res, ex) -> { - ex.printStackTrace(System.out); - req.next(); - }) - .error(NumberFormatException.class, - (req, res, ex) -> res.status(Http.Status.BAD_REQUEST_400).send()) - .error(ArithmeticException.class, - (req, res, ex) -> res.status(Http.Status.PRECONDITION_FAILED_412).send()) - .build(); - startServer(routing); - } - - - // ---------------- EXECUTION - - private static final String SYSPROP_EXAMPLE_NAME = "exampleName"; - private static final String ENVVAR_EXAMPLE_NAME = "EXAMPLE_NAME"; - - /** - * Prints usage instructions. - */ - public void help() { - StringBuilder hlp = new StringBuilder(); - hlp.append("java -jar example-basics.jar \n"); - hlp.append("Example method names:\n"); - Method[] methods = Main.class.getDeclaredMethods(); - for (Method method : methods) { - if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) { - hlp.append(" ").append(method.getName()).append('\n'); - } - } - hlp.append('\n'); - hlp.append("Example method name can be also provided as a\n"); - hlp.append(" - -D").append(SYSPROP_EXAMPLE_NAME).append(" jvm property.\n"); - hlp.append(" - ").append(ENVVAR_EXAMPLE_NAME).append(" environment variable.\n"); - System.out.println(hlp); - } - - /** - * Prints usage instructions. (Shortcut to {@link #help()} method. - */ - public void h() { - help(); - } - - /** - * Java main method. - * - * @param args Command line arguments. - */ - public static void main(String[] args) { - String exampleName = null; - if (args.length > 0) { - exampleName = args[0]; - } else if (System.getProperty(SYSPROP_EXAMPLE_NAME) != null) { - exampleName = System.getProperty(SYSPROP_EXAMPLE_NAME); - } else if (System.getenv(ENVVAR_EXAMPLE_NAME) != null) { - exampleName = System.getenv(ENVVAR_EXAMPLE_NAME); - } else { - System.out.println("Missing example name. It can be provided as a \n" - + " - first command line argument.\n" - + " - -D" + SYSPROP_EXAMPLE_NAME + " jvm property.\n" - + " - " + ENVVAR_EXAMPLE_NAME + " environment variable.\n"); - System.exit(1); - } - while (exampleName.startsWith("-")) { - exampleName = exampleName.substring(1); - } - Main m = new Main(); - try { - Method method = Main.class.getMethod(exampleName); - method.invoke(m); - } catch (NoSuchMethodException e) { - System.out.println("Missing example method named: " + exampleName); - System.exit(2); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(System.out); - System.exit(100); - } - } -} diff --git a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Name.java b/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Name.java deleted file mode 100644 index 189c7b0afac..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/Name.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.basics; - -/** - * Represents a simple entity - the name. - */ -public class Name { - - private final String firstName; - private final String middleName; - private final String lastName; - - /** - * An naive implementation of name parser. - * - * @param fullName a full name - */ - public Name(String fullName) { - String[] split = fullName.split(" "); - switch (split.length) { - case 0: - throw new IllegalArgumentException("An empty name"); - case 1: - firstName = null; - middleName = null; - lastName = split[0]; - break; - case 2: - firstName = split[0]; - middleName = null; - lastName = split[1]; - break; - case 3: - firstName = split[0]; - middleName = split[1]; - lastName = split[2]; - break; - default: - throw new IllegalArgumentException("To many name parts!"); - } - } - - public String getFirstName() { - return firstName; - } - - public String getMiddleName() { - return middleName; - } - - public String getLastName() { - return lastName; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (firstName != null) { - result.append(firstName); - } - if (middleName != null) { - if (result.length() > 0) { - result.append(' '); - } - result.append(middleName); - } - if (lastName != null) { - if (result.length() > 0) { - result.append(' '); - } - result.append(lastName); - } - return result.toString(); - } -} diff --git a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/NameReader.java b/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/NameReader.java deleted file mode 100644 index 183f66b584a..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/NameReader.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.webserver.examples.basics; - -import java.util.concurrent.Flow; - -import io.helidon.common.GenericType; -import io.helidon.common.http.DataChunk; -import io.helidon.common.http.MediaType; -import io.helidon.common.reactive.Single; -import io.helidon.media.common.ContentReaders; -import io.helidon.media.common.MessageBodyReader; -import io.helidon.media.common.MessageBodyReaderContext; - -/** - * Reader for the custom media type. - */ -public class NameReader implements MessageBodyReader { - - private static final MediaType TYPE = MediaType.parse("application/name"); - - private NameReader() { - } - - static NameReader create() { - return new NameReader(); - } - - @Override - public Single read(Flow.Publisher publisher, GenericType type, - MessageBodyReaderContext context) { - return (Single) ContentReaders.readString(publisher, context.charset()).map(Name::new); - } - - @Override - public PredicateResult accept(GenericType type, MessageBodyReaderContext context) { - return context.contentType() - .filter(TYPE::equals) - .map(it -> PredicateResult.supports(Name.class, type)) - .orElse(PredicateResult.NOT_SUPPORTED); - } -} - - - - diff --git a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/package-info.java b/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/package-info.java deleted file mode 100644 index 392eaa0ee3f..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/webserver/examples/basics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A set of small usage examples. Start with {@link io.helidon.webserver.examples.basics.Main Main} class. - */ -package io.helidon.webserver.examples.basics; diff --git a/examples/webserver/basics/src/main/resources/static/index.html b/examples/webserver/basics/src/main/resources/static/index.html deleted file mode 100644 index 82a701ccfb4..00000000000 --- a/examples/webserver/basics/src/main/resources/static/index.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - Just index - - -

    Example

    - - diff --git a/examples/webserver/basics/src/test/java/io/helidon/webserver/examples/basics/MainTest.java b/examples/webserver/basics/src/test/java/io/helidon/webserver/examples/basics/MainTest.java deleted file mode 100644 index d220c1c1414..00000000000 --- a/examples/webserver/basics/src/test/java/io/helidon/webserver/examples/basics/MainTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.basics; - -import java.util.function.Consumer; - -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.media.common.MediaContext; -import io.helidon.webserver.Routing; -import io.helidon.webserver.testsupport.MediaPublisher; -import io.helidon.webserver.testsupport.TestClient; -import io.helidon.webserver.testsupport.TestResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class MainTest { - - @Test - public void firstRouting() throws Exception { - // POST - TestResponse response = createClient(Main::firstRouting).path("/post-endpoint").post(); - assertThat(response.status().code(), is(201)); - // GET - response = createClient(Main::firstRouting).path("/get-endpoint").get(); - assertThat(response.status().code(), is(204)); - assertThat(response.asString().get(), is("Hello World!")); - } - - @Test - public void routingAsFilter() throws Exception { - // POST - TestResponse response = createClient(Main::routingAsFilter).path("/post-endpoint").post(); - assertThat(response.status().code(), is(201)); - // GET - response = createClient(Main::routingAsFilter).path("/get-endpoint").get(); - assertThat(response.status().code(), is(204)); - } - - @Test - public void parametersAndHeaders() throws Exception { - TestResponse response = createClient(Main::parametersAndHeaders).path("/context/aaa") - .queryParameter("bar", "bbb") - .header("foo", "ccc") - .get(); - assertThat(response.status().code(), is(200)); - String s = response.asString().get(); - assertThat(s, containsString("id: aaa")); - assertThat(s, containsString("bar: bbb")); - assertThat(s, containsString("foo: ccc")); - } - - @Test - public void organiseCode() throws Exception { - // List - TestResponse response = createClient(Main::organiseCode).path("/catalog-context-path").get(); - assertThat(response.status().code(), is(200)); - assertThat(response.asString().get(), is("1, 2, 3, 4, 5")); - // Get by id - response = createClient(Main::organiseCode).path("/catalog-context-path/aaa").get(); - assertThat(response.status().code(), is(200)); - assertThat(response.asString().get(), is("Item: aaa")); - } - - @Test - public void readContentEntity() throws Exception { - // foo - TestResponse response - = createClient(Main::readContentEntity).path("/foo") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "aaa")); - assertThat(response.status().code(), is(200)); - assertThat(response.asString().get(), is("aaa")); - // bar - response = createClient(Main::readContentEntity).path("/bar") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "aaa")); - assertThat(response.status().code(), is(200)); - assertThat(response.asString().get(), is("aaa")); - } - - @Test - public void mediaReader() throws Exception { - TestResponse response = createClient(Main::mediaReader) - .path("/create-record") - .post(MediaPublisher.create(MediaType.parse("application/name"), "John Smith")); - assertThat(response.status().code(), is(201)); - assertThat(response.asString().get(), is("John Smith")); - // Unsupported Content-Type - response = createClient(Main::mediaReader) - .path("/create-record") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "John Smith")); - assertThat(response.status().code(), is(500)); - } - - @Test - public void supports() throws Exception { - // Jersey - TestResponse response = createClient(Main::supports).path("/api/hw").get(); - assertThat(response.status().code(), is(200)); - assertThat(response.asString().get(), is("Hello world!")); - // Static content - response = createClient(Main::supports).path("/index.html").get(); - assertThat(response.status().code(), is(200)); - assertThat(response.headers().first(Http.Header.CONTENT_TYPE).orElse(null), is(MediaType.TEXT_HTML.toString())); - // JSON - response = createClient(Main::supports).path("/hello/Europe").get(); - assertThat(response.status().code(), is(200)); - assertThat(response.asString().get(), is("{\"message\":\"Hello Europe\"}")); - } - - @Test - public void errorHandling() throws Exception { - // Valid - TestResponse response = createClient(Main::errorHandling) - .path("/compute") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "2")); - assertThat(response.status().code(), is(200)); - assertThat(response.asString().get(), is("100 / 2 = 50")); - // Zero - response = createClient(Main::errorHandling) - .path("/compute") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "0")); - assertThat(response.status().code(), is(412)); - // NaN - response = createClient(Main::errorHandling) - .path("/compute") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "aaa")); - assertThat(response.status().code(), is(400)); - } - - private TestClient createClient(Consumer
    callTestedMethod) { - TMain tm = new TMain(); - callTestedMethod.accept(tm); - assertThat(tm.routing, notNullValue()); - return TestClient.create(tm.routing, tm.mediaContext); - } - - static class TMain extends Main { - - private Routing routing; - private MediaContext mediaContext; - - @Override - protected void startServer(Routing routing, MediaContext mediaContext) { - this.routing = routing; - this.mediaContext = mediaContext; - } - } -} diff --git a/examples/webserver/comment-aas/README.md b/examples/webserver/comment-aas/README.md deleted file mode 100644 index 37f16a96890..00000000000 --- a/examples/webserver/comment-aas/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Comments As a Service - -This application allows users to add or read short comments related to a single topic. - Topic can be anything including blog post, newspaper article, and others. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-webserver-comment-aas.jar -``` - -Try the application: - -```bash -curl http://localhost:8080/comments/java -d "I use Helidon!" -curl http://localhost:8080/comments/java -d "I use vertx" -curl http://localhost:8080/comments/java -d "I use spring" -curl http://localhost:8080/comments/java -``` diff --git a/examples/webserver/comment-aas/etc/add-comment b/examples/webserver/comment-aas/etc/add-comment deleted file mode 100755 index d76f88f21e5..00000000000 --- a/examples/webserver/comment-aas/etc/add-comment +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -f "$SCRIPT_DIR/user.txt" ]; then - export SVC_USER=`cat "$SCRIPT_DIR/user.txt"` -fi - -if [ -z "$2" ]; then - echo "Missing command line parameter! Usage: comment.sh " - exit 1 -fi - -if [ -z "$SVC_USER" ]; then - echo "Contacting service http://localhost:8080" - echo "" - curl --noproxy localhost -X POST --data "$2" http://localhost:8080/comments/$1 -else - echo "Contacting service http://localhost:8080 as $SVC_USER" - echo "" - curl --noproxy localhost -H "user-identity: $SVC_USER" -X POST --data "$2" http://localhost:8080/comments/$1 -fi -echo "" diff --git a/examples/webserver/comment-aas/etc/config.yaml b/examples/webserver/comment-aas/etc/config.yaml deleted file mode 100644 index 2601b6f8c9d..00000000000 --- a/examples/webserver/comment-aas/etc/config.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -anonymous-enabled: false diff --git a/examples/webserver/comment-aas/etc/create-etcd b/examples/webserver/comment-aas/etc/create-etcd deleted file mode 100755 index 6c5f1b1292e..00000000000 --- a/examples/webserver/comment-aas/etc/create-etcd +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -export SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -export ETCD_DATA_DIRS=/tmp/etcd-data/config-gerrit-etcd-data-dirs -rm -rf $ETCD_DATA_DIRS -export CONTAINER_NAME="config-etcd" - -docker rm -f $CONTAINER_NAME -export HOST_IP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'` - -docker run -d \ - -v $ETCD_DATA_DIRS:/var/data-dir \ - -p 2380:2380 \ - -p 2379:2379 \ - --name $CONTAINER_NAME \ - quay.io/coreos/etcd:v3.1.3 \ - etcd \ - -name etcd \ - -data-dir /var/data-dir \ - -advertise-client-urls http://$HOST_IP:2380 \ - -listen-client-urls http://0.0.0.0:2379 \ - -initial-advertise-peer-urls http://$HOST_IP:2380 \ - -listen-peer-urls http://0.0.0.0:2380 - -echo "Run with name $CONTAINER_NAME" - -echo "Test:" -docker exec $CONTAINER_NAME /bin/sh -c "ETCDCTL_API=3 etcdctl put my-key my-value" diff --git a/examples/webserver/comment-aas/etc/get-etcd-config b/examples/webserver/comment-aas/etc/get-etcd-config deleted file mode 100755 index eca74b3f078..00000000000 --- a/examples/webserver/comment-aas/etc/get-etcd-config +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -HOST_IP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'` - -echo "Retrieving configuration from ETCD:" -curl --noproxy $HOST_IP http://$HOST_IP:2379/v2/keys/comments-aas-config | python -m json.tool diff --git a/examples/webserver/comment-aas/etc/list-comments b/examples/webserver/comment-aas/etc/list-comments deleted file mode 100755 index 18cc0ec5997..00000000000 --- a/examples/webserver/comment-aas/etc/list-comments +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -f "$SCRIPT_DIR/user.txt" ]; then - export SVC_USER=`cat "$SCRIPT_DIR/user.txt"` -fi - -if [ -z "$1" ]; then - echo "Missing command line parameter! Usage: list_comments.sh " - exit 1 -fi - -if [ -z "$SVC_USER" ]; then - echo "Contacting service http://localhost:8080" - echo "" - curl --noproxy localhost http://localhost:8080/comments/$1 -else - echo "Contacting service http://localhost:8080 as $SVC_USER" - echo "" - curl --noproxy localhost -H "user-identity: $SVC_USER" http://localhost:8080/comments/$1 -fi -echo "" diff --git a/examples/webserver/comment-aas/etc/put-etcd-config b/examples/webserver/comment-aas/etc/put-etcd-config deleted file mode 100755 index 0ca9f6b9aa1..00000000000 --- a/examples/webserver/comment-aas/etc/put-etcd-config +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -HOST_IP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'` -CONFIG_FILE="$SCRIPT_DIR/config.yaml" - -if [ -f "$CONFIG_FILE" ]; then - echo "Storing configuration into ETCD: $CONFIG_FILE" - curl --noproxy $HOST_IP -vvv http://$HOST_IP:2379/v2/keys/comments-aas-config -XPUT --data-urlencode value@$CONFIG_FILE -else - echo "Configuration file $CONFIG_FILE not found. DO NOT IMPORT INTO ETCD!" -fi diff --git a/examples/webserver/comment-aas/etc/start-etcd b/examples/webserver/comment-aas/etc/start-etcd deleted file mode 100755 index c3ae59070f6..00000000000 --- a/examples/webserver/comment-aas/etc/start-etcd +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -CONTAINER_NAME="config-etcd" -docker start $CONTAINER_NAME diff --git a/examples/webserver/comment-aas/etc/stop-comment-service b/examples/webserver/comment-aas/etc/stop-comment-service deleted file mode 100755 index 21def952ce1..00000000000 --- a/examples/webserver/comment-aas/etc/stop-comment-service +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -f "$SCRIPT_DIR/user.txt" ]; then - export SVC_USER=`cat "$SCRIPT_DIR/user.txt"` -fi - -if [ -z "$SVC_USER" ]; then - echo "Contacting service http://localhost:8080" - echo "" - curl --noproxy localhost -X POST http://localhost:8080/mgmt/shutdown -else - echo "Contacting service http://localhost:8080 as $SVC_USER" - echo "" - curl --noproxy localhost -H "user-identity: $SVC_USER" -X POST http://localhost:8080/mgmt/shutdown -fi -echo "" diff --git a/examples/webserver/comment-aas/etc/stop-etcd b/examples/webserver/comment-aas/etc/stop-etcd deleted file mode 100755 index e54f1ea70e0..00000000000 --- a/examples/webserver/comment-aas/etc/stop-etcd +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -CONTAINER_NAME="config-etcd" -docker stop $CONTAINER_NAME diff --git a/examples/webserver/comment-aas/etc/switch-user b/examples/webserver/comment-aas/etc/switch-user deleted file mode 100755 index 49740ba3a90..00000000000 --- a/examples/webserver/comment-aas/etc/switch-user +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -z "$1" ]; then - echo "set empty context user!" - rm -f "$SCRIPT_DIR/user.txt" -else - echo "set context user: $1" - echo "$1" > "$SCRIPT_DIR/user.txt" -fi diff --git a/examples/webserver/comment-aas/pom.xml b/examples/webserver/comment-aas/pom.xml deleted file mode 100644 index fe05bf6fe13..00000000000 --- a/examples/webserver/comment-aas/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-comment-aas - Helidon WebServer Examples CommentsAAS - - Comments As A Service example application - - - io.helidon.webserver.examples.comments.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.common - helidon-common - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/CommentsService.java b/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/CommentsService.java deleted file mode 100644 index d2320c8033f..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/CommentsService.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.comments; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import io.helidon.common.http.MediaType; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * Basic service for comments. - */ -@SuppressWarnings("Duplicates") -public class CommentsService implements Service { - - private final ConcurrentHashMap> topicsAndComments = new ConcurrentHashMap<>(); - - @Override - public void update(Routing.Rules routingRules) { - routingRules - .get("/{topic}", this::handleListComments) - .post("/{topic}", this::handleAddComment); - } - - private void handleListComments(ServerRequest req, ServerResponse resp) { - String topic = req.path().param("topic"); - resp.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - resp.send(listComments(topic)); - } - - private void handleAddComment(ServerRequest req, ServerResponse resp) { - String topic = req.path().param("topic"); - - String userName = req.context().get("user", String.class) - .orElse("anonymous"); - - req.content() - .as(String.class) - .thenAccept(msg -> addComment(msg, userName, topic)) - .thenRun(resp::send) - .exceptionally(t -> { - req.next(t); - return null; - }); - } - - /** - * Adds new comment into the comment-room. - * - * @param message a comment message - * @param fromUser a user alias of the comment author - */ - void addComment(String message, String fromUser, String toTopic) { - ProfanityDetector.detectProfanity(message); - if (fromUser == null) { - fromUser = "anonymous"; - } - List comments = - topicsAndComments.computeIfAbsent(toTopic, k -> Collections.synchronizedList(new ArrayList<>())); - comments.add(new Comment(fromUser, message)); - } - - /** - * List all comments in original order as a string with single comment on the line. - * - * @param roomName a name of the room - * @return all comments, line-by-line - */ - String listComments(String roomName) { - List comments = topicsAndComments.get(roomName); - if (comments != null) { - return comments.stream() - .map(String::valueOf) - .collect(Collectors.joining("\n")); - } else { - return ""; - } - } - - private static class Comment { - private final String userName; - private final String message; - - Comment(String userName, String message) { - this.userName = userName; - this.message = message; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (userName != null) { - result.append(userName); - } - result.append(": "); - result.append(message); - return result.toString(); - } - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/Main.java b/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/Main.java deleted file mode 100644 index 47782a56e79..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/Main.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017, 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.webserver.examples.comments; - -import java.util.Optional; -import java.util.concurrent.CompletionException; - -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.HttpException; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Application java main class. - *

    - *

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

    - *

    This WEB application provides possibility to store and read comment related to various topics. - */ -public final class Main { - - private Main() { - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - // Load configuration - Config config = Config.create(); - - boolean acceptAnonymousUsers = config.get("anonymous-enabled").asBoolean().orElse(false); - - WebServer server = WebServer.create(createRouting(acceptAnonymousUsers), - config.get("webserver")); - - // Start the server and print some info. - server.start().thenAccept((ws) -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port() + "/comments"); - }); - - server.whenShutdown() - .thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - } - - static Routing createRouting(boolean acceptAnonymousUsers) { - return Routing.builder() - // Filter that translates user identity header into the contextual "user" information - .any((req, res) -> { - String user = req.headers().first("user-identity") - .or(() -> acceptAnonymousUsers ? Optional.of("anonymous") : Optional.empty()) - .orElseThrow(() -> new HttpException("Anonymous access is forbidden!", Http.Status.FORBIDDEN_403)); - - req.context().register("user", user); - req.next(); - }) - // Main service logic part is registered as a separated class to "/comments" context root - .register("/comments", new CommentsService()) - // Error handling for argot expressions. - .error(CompletionException.class, (req, res, ex) -> req.next(ex.getCause())) - .error(ProfanityException.class, (req, res, ex) -> { - res.status(Http.Status.NOT_ACCEPTABLE_406); - res.send("Expressions like '" + ex.getObfuscatedProfanity() + "' are unacceptable!"); - }) - .error(HttpException.class, (req, res, ex) -> { - if (ex.status() == Http.Status.FORBIDDEN_403) { - res.status(ex.status()); - res.send(ex.getMessage()); - } else { - req.next(); - } - }) - .build(); - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityDetector.java b/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityDetector.java deleted file mode 100644 index aced95ae9fe..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityDetector.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.comments; - -/** - * Simple profanity detection utility class. - */ -class ProfanityDetector { - private static final String[] BANNED_TERMS = new String[] {"spring", "nodejs", "vertx"}; - - private ProfanityDetector() { - } - - /** - * Detects if a message contains one of the profane words. - * - * @param message a message to check. - */ - static void detectProfanity(String message) { - if (message == null) { - return; - } - message = message.toLowerCase(); - for (String bannedTerm : BANNED_TERMS) { - if (message.contains(bannedTerm)) { - throw new ProfanityException(bannedTerm); - } - } - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityException.java b/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityException.java deleted file mode 100644 index c7bd031712e..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/ProfanityException.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.comments; - -/** - * Thrown to indicate that a message contains illegal argot word. - */ -public class ProfanityException extends IllegalArgumentException { - - private final String profanity; - - /** - * Creates new instance. - * - * @param profanity an illegal argot word. - */ - public ProfanityException(String profanity) { - super("Do not use such an ugly word as '" + obfuscate(profanity) + "'!"); - this.profanity = profanity; - } - - /** - * Returns an illegal argot word! - * - * @return an argot word - */ - public String getProfanity() { - return profanity; - } - - /** - * Returns an illegal argot word in obfuscated form! - * - * @return an argot word in obfuscated form - */ - public String getObfuscatedProfanity() { - return obfuscate(profanity); - } - - private static String obfuscate(String argot) { - if (argot == null || argot.length() < 2) { - return argot; - } - if (argot.length() == 2) { - return argot.charAt(0) + "*"; - } - return argot.charAt(0) + "*" + argot.charAt(argot.length() - 1); - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/package-info.java b/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/package-info.java deleted file mode 100644 index a6ed23c8782..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/webserver/examples/comments/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The COMMENTS-As-a-Service application example demonstrates Web Server in its integration role. - * It integrates various components including Configuration and Security. - * - *

    This WEB application provides possibility to store and read comment related to various topics. - */ -package io.helidon.webserver.examples.comments; diff --git a/examples/webserver/comment-aas/src/main/resources/application.yaml b/examples/webserver/comment-aas/src/main/resources/application.yaml deleted file mode 100644 index 80abf83fbee..00000000000 --- a/examples/webserver/comment-aas/src/main/resources/application.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -webserver: - port: 8080 - -# If true then anonymous access is enabled. -anonymous-enabled: true diff --git a/examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/CommentsServiceTest.java b/examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/CommentsServiceTest.java deleted file mode 100644 index 887e8b07fd2..00000000000 --- a/examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/CommentsServiceTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.comments; - -import java.nio.charset.StandardCharsets; - -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.webserver.Routing; -import io.helidon.webserver.testsupport.MediaPublisher; -import io.helidon.webserver.testsupport.TestClient; -import io.helidon.webserver.testsupport.TestResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.isEmptyString; - - -/** - * Tests {@link CommentsService}. - */ -public class CommentsServiceTest { - - @Test - public void addAndGetComments() throws Exception { - CommentsService service = new CommentsService(); - assertThat(service.listComments("one"), isEmptyString()); - assertThat(service.listComments("two"), isEmptyString()); - - service.addComment("aaa", null, "one"); - assertThat(service.listComments("one"), is("anonymous: aaa")); - assertThat(service.listComments("two"), isEmptyString()); - - service.addComment("bbb", "Foo", "one"); - assertThat(service.listComments("one"), is("anonymous: aaa\nFoo: bbb")); - assertThat(service.listComments("two"), isEmptyString()); - - service.addComment("bbb", "Bar", "two"); - assertThat(service.listComments("one"), is("anonymous: aaa\nFoo: bbb")); - assertThat(service.listComments("two"), is("Bar: bbb")); - } - - @Test - public void testRouting() throws Exception { - Routing routing = Routing.builder() - .register(new CommentsService()) - .build(); - TestResponse response = TestClient.create(routing) - .path("one") - .get(); - assertThat(response.status(), is(Http.Status.OK_200)); - - response = TestClient.create(routing) - .path("one") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "aaa")); - assertThat(response.status(), is(Http.Status.OK_200)); - - response = TestClient.create(routing) - .path("one") - .get(); - assertThat(response.status(), is(Http.Status.OK_200)); - byte[] data = response.asBytes().toCompletableFuture().join(); - assertThat(new String(data, StandardCharsets.UTF_8), is("anonymous: aaa")); - } - -} diff --git a/examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/MainTest.java b/examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/MainTest.java deleted file mode 100644 index e1e2332cdd4..00000000000 --- a/examples/webserver/comment-aas/src/test/java/io/helidon/webserver/examples/comments/MainTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.comments; - -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.webserver.testsupport.MediaPublisher; -import io.helidon.webserver.testsupport.TestClient; -import io.helidon.webserver.testsupport.TestResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Tests {@link Main} class. - */ -public class MainTest { - - @Test - public void argot() throws Exception { - TestResponse response = TestClient.create(Main.createRouting(true)) - .path("/comments/one") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "Spring framework is the BEST!")); - assertThat(response.status(), is(Http.Status.NOT_ACCEPTABLE_406)); - } - - @Test - public void anonymousDisabled() throws Exception { - TestResponse response = TestClient.create(Main.createRouting(false)) - .path("/comment/one") - .get(); - - assertThat(response.status(), is(Http.Status.FORBIDDEN_403)); - } -} diff --git a/examples/webserver/fault-tolerance/pom.xml b/examples/webserver/fault-tolerance/pom.xml deleted file mode 100644 index 7ac17a788c0..00000000000 --- a/examples/webserver/fault-tolerance/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-fault-tolerance - Helidon WebServer Examples FT - - - Application demonstrates Fault tolerance used in webserver. - - - - io.helidon.webserver.examples.faulttolerance.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.fault-tolerance - helidon-fault-tolerance - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/FtService.java b/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/FtService.java deleted file mode 100644 index 8154b296d81..00000000000 --- a/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/FtService.java +++ /dev/null @@ -1,168 +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.webserver.examples.faulttolerance; - -import java.time.Duration; -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.common.reactive.Single; -import io.helidon.faulttolerance.Async; -import io.helidon.faulttolerance.Bulkhead; -import io.helidon.faulttolerance.CircuitBreaker; -import io.helidon.faulttolerance.Fallback; -import io.helidon.faulttolerance.Retry; -import io.helidon.faulttolerance.Timeout; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * Simple service to demonstrate fault tolerance. - */ -public class FtService implements Service { - - private final Async async; - private final Bulkhead bulkhead; - private final CircuitBreaker breaker; - private final Fallback fallback; - private final Retry retry; - private final Timeout timeout; - - FtService() { - this.async = Async.create(); - this.bulkhead = Bulkhead.builder() - .queueLength(1) - .limit(1) - .name("helidon-example-bulkhead") - .build(); - this.breaker = CircuitBreaker.builder() - .volume(4) - .errorRatio(40) - .successThreshold(1) - .delay(Duration.ofSeconds(5)) - .build(); - this.fallback = Fallback.create(this::fallbackToMethod); - this.retry = Retry.builder() - .retryPolicy(Retry.DelayingRetryPolicy.noDelay(3)) - .build(); - this.timeout = Timeout.create(Duration.ofMillis(100)); - } - - @Override - public void update(Routing.Rules rules) { - rules.get("/async", this::asyncHandler) - .get("/bulkhead/{millis}", this::bulkheadHandler) - .get("/circuitBreaker/{success}", this::circuitBreakerHandler) - .get("/fallback/{success}", this::fallbackHandler) - .get("/retry/{count}", this::retryHandler) - .get("/timeout/{millis}", this::timeoutHandler); - } - - private void timeoutHandler(ServerRequest request, ServerResponse response) { - long sleep = Long.parseLong(request.path().param("millis")); - - timeout.invoke(() -> sleep(sleep)) - .thenAccept(response::send) - .exceptionally(response::send); - } - - private void retryHandler(ServerRequest request, ServerResponse response) { - int count = Integer.parseInt(request.path().param("count")); - - AtomicInteger call = new AtomicInteger(1); - AtomicInteger failures = new AtomicInteger(); - - retry.invoke(() -> { - int current = call.getAndIncrement(); - if (current < count) { - failures.incrementAndGet(); - return reactiveFailure(); - } - return Single.just("calls/failures: " + current + "/" + failures.get()); - }).thenAccept(response::send) - .exceptionally(response::send); - } - - private void fallbackHandler(ServerRequest request, ServerResponse response) { - boolean success = "true".equalsIgnoreCase(request.path().param("success")); - - if (success) { - fallback.invoke(this::reactiveData).thenAccept(response::send); - } else { - fallback.invoke(this::reactiveFailure).thenAccept(response::send); - } - } - - private void circuitBreakerHandler(ServerRequest request, ServerResponse response) { - boolean success = "true".equalsIgnoreCase(request.path().param("success")); - - if (success) { - breaker.invoke(this::reactiveData) - .thenAccept(response::send) - .exceptionally(response::send); - } else { - breaker.invoke(this::reactiveFailure) - .thenAccept(response::send) - .exceptionally(response::send); - } - - } - - private void bulkheadHandler(ServerRequest request, ServerResponse response) { - long sleep = Long.parseLong(request.path().param("millis")); - - bulkhead.invoke(() -> sleep(sleep)) - .thenAccept(response::send) - .exceptionally(response::send); - } - - private void asyncHandler(ServerRequest request, ServerResponse response) { - async.invoke(this::blockingData).thenApply(response::send); - } - - private Single reactiveFailure() { - return Single.error(new RuntimeException("reactive failure")); - } - - private Single sleep(long sleepMillis) { - return async.invoke(() -> { - try { - Thread.sleep(sleepMillis); - } catch (InterruptedException ignored) { - } - return "Slept for " + sleepMillis + " ms"; - }); - } - - private Single reactiveData() { - return async.invoke(this::blockingData); - } - - private String blockingData() { - try { - Thread.sleep(100); - } catch (InterruptedException ignored) { - } - return "blocked for 100 millis"; - } - - private Single fallbackToMethod(Throwable e) { - return Single.just("Failed back because of " + e.getMessage()); - } - -} diff --git a/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/Main.java b/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/Main.java deleted file mode 100644 index fb023f7e137..00000000000 --- a/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/Main.java +++ /dev/null @@ -1,74 +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.webserver.examples.faulttolerance; - -import java.util.concurrent.TimeoutException; - -import io.helidon.common.LogConfig; -import io.helidon.common.http.Http; -import io.helidon.common.reactive.Single; -import io.helidon.faulttolerance.BulkheadException; -import io.helidon.faulttolerance.CircuitBreakerOpenException; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Main class of Fault tolerance example. - */ -public final class Main { - // utility class - private Main() { - } - - /** - * Start the example. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - startServer(8079).thenRun(() -> {}); - } - - static Single startServer(int port) { - return WebServer.builder() - .routing(routing()) - .port(port) - .build() - .start() - .peek(server -> { - String url = "http://localhost:" + server.port(); - System.out.println("Server started on " + url); - }); - } - - private static Routing routing() { - return Routing.builder() - .register("/ft", new FtService()) - .error(BulkheadException.class, - (req, res, ex) -> res.status(Http.Status.SERVICE_UNAVAILABLE_503).send("bulkhead")) - .error(CircuitBreakerOpenException.class, - (req, res, ex) -> res.status(Http.Status.SERVICE_UNAVAILABLE_503).send("circuit breaker")) - .error(TimeoutException.class, - (req, res, ex) -> res.status(Http.Status.REQUEST_TIMEOUT_408).send("timeout")) - .error(Throwable.class, - (req, res, ex) -> res.status(Http.Status.INTERNAL_SERVER_ERROR_500) - .send(ex.getClass().getName() + ": " + ex.getMessage())) - .build(); - } -} diff --git a/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/package-info.java b/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/package-info.java deleted file mode 100644 index f19f38365b2..00000000000 --- a/examples/webserver/fault-tolerance/src/main/java/io/helidon/webserver/examples/faulttolerance/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of Fault Tolerance usage in webserver. - */ -package io.helidon.webserver.examples.faulttolerance; diff --git a/examples/webserver/fault-tolerance/src/main/resources/logging.properties b/examples/webserver/fault-tolerance/src/main/resources/logging.properties deleted file mode 100644 index 59efab32c1b..00000000000 --- a/examples/webserver/fault-tolerance/src/main/resources/logging.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.server.level=INFO - -#io.helidon.faulttolerance.level=FINEST diff --git a/examples/webserver/fault-tolerance/src/test/java/io/helidon/webserver/examples/faulttolerance/MainTest.java b/examples/webserver/fault-tolerance/src/test/java/io/helidon/webserver/examples/faulttolerance/MainTest.java deleted file mode 100644 index e90d960b210..00000000000 --- a/examples/webserver/fault-tolerance/src/test/java/io/helidon/webserver/examples/faulttolerance/MainTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.faulttolerance; - -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -class MainTest { - private static WebServer server; - private static WebClient client; - - @BeforeAll - static void initClass() { - server = Main.startServer(0) - .await(10, TimeUnit.SECONDS); - - client = WebClient.builder() - .baseUri("http://localhost:" + server.port() + "/ft") - .build(); - } - - @AfterAll - static void destroyClass() { - server.shutdown() - .await(5, TimeUnit.SECONDS); - } - - @Test - void testAsync() { - String response = client.get() - .path("/async") - .request(String.class) - .await(5, TimeUnit.SECONDS); - - assertThat(response, is("blocked for 100 millis")); - } - - @Test - void testBulkhead() throws InterruptedException { - // bulkhead is configured for limit of 1 and queue of 1, so third - // request should fail - client.get() - .path("/bulkhead/10000") - .request(); - - client.get() - .path("/bulkhead/10000") - .request(); - - // I want to make sure the above is connected - Thread.sleep(300); - - WebClientResponse third = client.get() - .path("/bulkhead/10000") - .request() - .await(1, TimeUnit.SECONDS); - - // registered an error handler in Main - assertThat(third.status(), is(Http.Status.SERVICE_UNAVAILABLE_503)); - assertThat(third.content().as(String.class).await(1, TimeUnit.SECONDS), is("bulkhead")); - } - - @Test - void testCircuitBreaker() { - String response = client.get() - .path("/circuitBreaker/true") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("blocked for 100 millis")); - - // error ratio is 20% within 10 request - client.get() - .path("/circuitBreaker/false") - .request() - .await(1, TimeUnit.SECONDS); - - // should work after first - response = client.get() - .path("/circuitBreaker/true") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("blocked for 100 millis")); - - // should open after second - client.get() - .path("/circuitBreaker/false") - .request() - .await(1, TimeUnit.SECONDS); - - WebClientResponse clientResponse = client.get() - .path("/circuitBreaker/true") - .request() - .await(1, TimeUnit.SECONDS); - response = clientResponse.content().as(String.class).await(1, TimeUnit.SECONDS); - - // registered an error handler in Main - assertThat(clientResponse.status(), is(Http.Status.SERVICE_UNAVAILABLE_503)); - assertThat(response, is("circuit breaker")); - } - - @Test - void testFallback() { - String response = client.get() - .path("/fallback/true") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("blocked for 100 millis")); - - response = client.get() - .path("/fallback/false") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("Failed back because of reactive failure")); - } - - @Test - void testRetry() { - String response = client.get() - .path("/retry/1") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("calls/failures: 1/0")); - - response = client.get() - .path("/retry/2") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("calls/failures: 2/1")); - - response = client.get() - .path("/retry/3") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("calls/failures: 3/2")); - - WebClientResponse clientResponse = client.get() - .path("/retry/4") - .request() - .await(1, TimeUnit.SECONDS); - - response = clientResponse.content().as(String.class).await(1, TimeUnit.SECONDS); - // no error handler specified - assertThat(clientResponse.status(), is(Http.Status.INTERNAL_SERVER_ERROR_500)); - assertThat(response, is("java.lang.RuntimeException: reactive failure")); - } - - @Test - void testTimeout() { - String response = client.get() - .path("/timeout/10") - .request(String.class) - .await(1, TimeUnit.SECONDS); - - assertThat(response, is("Slept for 10 ms")); - - WebClientResponse clientResponse = client.get() - .path("/timeout/1000") - .request() - .await(1, TimeUnit.SECONDS); - - response = clientResponse.content().as(String.class).await(1, TimeUnit.SECONDS); - // error handler specified in Main - assertThat(clientResponse.status(), is(Http.Status.REQUEST_TIMEOUT_408)); - assertThat(response, is("timeout")); - } -} \ No newline at end of file diff --git a/examples/webserver/jersey/README.md b/examples/webserver/jersey/README.md deleted file mode 100644 index 620d41954c2..00000000000 --- a/examples/webserver/jersey/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# WebServer Jersey Application Example - -An example of **Jersey** integration into the **Web Server**. - -This is just a simple Hello World example. A user can start the application using the `WebServerJerseyMain` class -and `GET` the `Hello World!` response by accessing `http://localhost:8080/jersey/hello`. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-webserver-jersey.jar -``` - -Make an HTTP request to application: -```bash -curl http://localhost:8080/jersey/hello -``` diff --git a/examples/webserver/jersey/pom.xml b/examples/webserver/jersey/pom.xml deleted file mode 100644 index 92166d272d8..00000000000 --- a/examples/webserver/jersey/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-jersey - Helidon WebServer Examples Jersey - - - WebServer Jersey example application - - - - io.helidon.webserver.examples.jersey.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-jersey - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/HelloWorld.java b/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/HelloWorld.java deleted file mode 100644 index f0bad750645..00000000000 --- a/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/HelloWorld.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.jersey; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; - -/** - * The Hello World Example JAX-RS resource. - */ -@Path("/") -public class HelloWorld { - - /** - * A simple resource returning {@code Hello World!} string. - * - * @return {@code Hello World!} string as a response - */ - @GET - @Path("hello") - public Response hello() { - return Response.ok("Hello World!").build(); - } -} diff --git a/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/Main.java b/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/Main.java deleted file mode 100644 index 42805e3712a..00000000000 --- a/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/Main.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017, 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.webserver.examples.jersey; - -import java.util.concurrent.CompletionStage; - -import io.helidon.common.LogConfig; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.jersey.JerseySupport; - -import org.glassfish.jersey.server.ResourceConfig; - -/** - * The WebServer Jersey Main example class. - * - * @see #main(String[]) - * @see #startServer(int) - */ -public final class Main { - - private Main() { - } - - /** - * Run the Jersey WebServer Example. - * - * @param args arguments are not used - */ - public static void main(String[] args) { - // configure logging in order to not have the standard JVM defaults - LogConfig.configureRuntime(); - - // start the server on port 8080 - startServer(8080); - } - - /** - * Start the WebServer based on the provided configuration. When running from - * a test, pass {@link null} to have a dynamically allocated port - * the server listens on. - * - * @param port port to start server on - * @return a completion stage indicating that the server has started and is ready to - * accept http requests - */ - static CompletionStage startServer(int port) { - WebServer webServer = WebServer.builder( - Routing.builder() - // register a Jersey Application at the '/jersey' context path - .register("/jersey", - JerseySupport.create(new ResourceConfig(HelloWorld.class))) - .build()) - .port(port) - .build(); - - return webServer.start() - .whenComplete((server, t) -> { - System.out.println("Jersey WebServer started."); - System.out.println("To stop the application, hit CTRL+C"); - System.out.println("Try the hello world resource at: http://localhost:" + server - .port() + "/jersey/hello"); - }); - } -} diff --git a/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/package-info.java b/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/package-info.java deleted file mode 100644 index 87748e2e68d..00000000000 --- a/examples/webserver/jersey/src/main/java/io/helidon/webserver/examples/jersey/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * An example of Jersey integration into the Web Server. - * - * @see io.helidon.webserver.jersey.JerseySupport - * @see io.helidon.webserver.WebServer - */ -package io.helidon.webserver.examples.jersey; diff --git a/examples/webserver/jersey/src/main/resources/logging.properties b/examples/webserver/jersey/src/main/resources/logging.properties deleted file mode 100644 index c71d4b6eb0f..00000000000 --- a/examples/webserver/jersey/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -#All attributes details -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#All log level details -.level=WARNING - -io.helidon.webserver.level=INFO -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/webserver/jersey/src/test/java/io/helidon/webserver/examples/jersey/HelloWorldTest.java b/examples/webserver/jersey/src/test/java/io/helidon/webserver/examples/jersey/HelloWorldTest.java deleted file mode 100644 index cc31a5ed03a..00000000000 --- a/examples/webserver/jersey/src/test/java/io/helidon/webserver/examples/jersey/HelloWorldTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.jersey; - -import java.util.concurrent.TimeUnit; - -import io.helidon.webserver.WebServer; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * The Jersey Client based example that tests the {@link HelloWorld} resource - * that gets served by running {@link Main#startServer(int)} - * - * @see HelloWorld - * @see Main - */ -public class HelloWorldTest { - - private static WebServer webServer; - - @BeforeAll - public static void startTheServer() throws Exception { - webServer = Main.startServer(0) - .toCompletableFuture() - .get(10, TimeUnit.SECONDS); - } - - @AfterAll - public static void stopServer() throws Exception { - if (webServer != null) { - webServer.shutdown() - .toCompletableFuture() - .get(10, TimeUnit.SECONDS); - } - } - - @Test - public void testHelloWorld() throws Exception { - Client client = ClientBuilder.newClient(); - try (Response response = client.target("http://localhost:" + webServer.port()) - .path("jersey/hello") - .request() - .get()) { - assertThat("Unexpected response; status: " + response.getStatus(), - response.readEntity(String.class), is("Hello World!")); - } finally { - client.close(); - } - } -} diff --git a/examples/webserver/multiport/README.md b/examples/webserver/multiport/README.md deleted file mode 100644 index f028517f3c1..00000000000 --- a/examples/webserver/multiport/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Helidon WebServer Multiple Port Example - -It is common when deploying a microservice to run your service on -multiple ports so that you can control the visibility of your -service's endpoints. For example you might want to use three ports: - -- 8080: public REST endpoints of application -- 8081: private REST endpoints of application -- 8082: admin endpoints for health, metrics, etc. - -This lets you expose only the public endpoints via your -ingress controller or load balancer. - -This example shows a Helidon application running on three ports -as described above. - -The ports are configured in `application.yaml` by using named sockets. - -Seperate routing is defined for each named socket in `Main.java` - -## Build and run - -With JDK11+ -```bash -mvn package -java -jar target/helidon-examples-webserver-multiport.jar -``` -## Exercise the application - -``` -curl -X GET http://localhost:8080/hello - -curl -X GET http://localhost:8081/private/hello - -curl -X GET http://localhost:8082/health - -curl -X GET http://localhost:8082/metrics -``` diff --git a/examples/webserver/multiport/pom.xml b/examples/webserver/multiport/pom.xml deleted file mode 100644 index 3701b934895..00000000000 --- a/examples/webserver/multiport/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-multiport - Helidon WebServer Examples Multiple Ports - - - io.helidon.examples.webserver.multiport.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-params - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/Main.java b/examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/Main.java deleted file mode 100644 index b8906b95c5c..00000000000 --- a/examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/Main.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.webserver.multiport; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(final String[] args) { - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - startServer(config); - } - - /** - * Start the server. - * @return the created {@link WebServer} instance - */ - static Single startServer(Config config) { - // load logging configuration - LogConfig.configureRuntime(); - - // Build server using three ports: - // default public port, admin port, private port - WebServer server = WebServer.builder(createPublicRouting()) - .config(config.get("server")) - // Add a set of routes on the named socket "admin" - .addNamedRouting("admin", createAdminRouting()) - // Add a set of routes on the named socket "private" - .addNamedRouting("private", createPrivateRouting()) - .build(); - - Single webserver = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webserver.thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port()); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - - // Server threads are not daemon. No need to block. Just react. - - return webserver; - } - - /** - * Creates private {@link Routing}. - * - * @return routing for use on "private" port - */ - private static Routing createPrivateRouting() { - return Routing.builder() - .get("/private/hello", (req, res) -> res.send("Private Hello!!")) - .build(); - } - - /** - * Creates public {@link Routing}. - * - * @return routing for use on "public" port - */ - private static Routing createPublicRouting() { - return Routing.builder() - .get("/hello", (req, res) -> res.send("Public Hello!!")) - .build(); - } - - /** - * Creates admin {@link Routing}. - * - * @return routing for use on admin port - */ - private static Routing createAdminRouting() { - MetricsSupport metrics = MetricsSupport.create(); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - - return Routing.builder() - .register(health) - .register(metrics) - .build(); - } -} diff --git a/examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/package-info.java b/examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/package-info.java deleted file mode 100644 index 89a5dad55f8..00000000000 --- a/examples/webserver/multiport/src/main/java/io/helidon/examples/webserver/multiport/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Application that exposes multiple ports. - */ -package io.helidon.examples.webserver.multiport; diff --git a/examples/webserver/multiport/src/main/resources/application.yaml b/examples/webserver/multiport/src/main/resources/application.yaml deleted file mode 100644 index f77248bd3e1..00000000000 --- a/examples/webserver/multiport/src/main/resources/application.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -server: - port: 8080 - host: "localhost" - sockets: - - name: "private" - port: 8081 - bind-address: "localhost" - - name: "admin" - port: 8082 - bind-address: "localhost" diff --git a/examples/webserver/multiport/src/main/resources/logging.properties b/examples/webserver/multiport/src/main/resources/logging.properties deleted file mode 100644 index aced7e48602..00000000000 --- a/examples/webserver/multiport/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/webserver/multiport/src/test/java/io/helidon/examples/webserver/multiport/MainTest.java b/examples/webserver/multiport/src/test/java/io/helidon/examples/webserver/multiport/MainTest.java deleted file mode 100644 index a4f51794d09..00000000000 --- a/examples/webserver/multiport/src/test/java/io/helidon/examples/webserver/multiport/MainTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.webserver.multiport; - -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; - -import io.helidon.common.http.Http; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - private static int publicPort; - private static int privatePort; - private static int adminPort; - - @BeforeAll - public static void startTheServer() { - // Use test configuration so we can have ports allocated dynamically - Config config = Config.builder().addSource(ConfigSources.classpath("application-test.yaml")).build(); - Single w = Main.startServer(config); - webServer = w.await(); - webClient = WebClient.builder().build(); - - publicPort = webServer.port(); - privatePort = webServer.port("private"); - adminPort = webServer.port("admin"); - } - - static Stream initParams() { - final String PUBLIC_PATH = "/hello"; - final String PRIVATE_PATH = "/private/hello"; - final String HEALTH_PATH = "/health"; - final String METRICS_PATH = "/health"; - - return List.of( - new Params(publicPort, PUBLIC_PATH, Http.Status.OK_200), - new Params(publicPort, PRIVATE_PATH, Http.Status.NOT_FOUND_404), - new Params(publicPort, HEALTH_PATH, Http.Status.NOT_FOUND_404), - new Params(publicPort, METRICS_PATH, Http.Status.NOT_FOUND_404), - - new Params(privatePort, PUBLIC_PATH, Http.Status.NOT_FOUND_404), - new Params(privatePort, PRIVATE_PATH, Http.Status.OK_200), - new Params(privatePort, HEALTH_PATH, Http.Status.NOT_FOUND_404), - new Params(privatePort, METRICS_PATH, Http.Status.NOT_FOUND_404), - - new Params(adminPort, PUBLIC_PATH, Http.Status.NOT_FOUND_404), - new Params(adminPort, PRIVATE_PATH, Http.Status.NOT_FOUND_404), - new Params(adminPort, HEALTH_PATH, Http.Status.OK_200), - new Params(adminPort, METRICS_PATH, Http.Status.OK_200) - ).stream(); - } - - @AfterAll - public static void stopServer() throws Exception { - if (webServer != null) { - webServer.shutdown() - .toCompletableFuture() - .get(10, TimeUnit.SECONDS); - } - } - - @MethodSource("initParams") - @ParameterizedTest - public void portAccessTest(Params params) throws Exception { - // Verifies we can access endpoints only on the proper port - webClient.get() - .uri("http://localhost:" + params.port) - .path(params.path) - .request() - .thenAccept(response -> assertThat(response.status(), is(params.httpStatus))) - .toCompletableFuture() - .get(); - } - - @Test - public void portTest() throws Exception { - - webClient.get() - .uri("http://localhost:" + publicPort) - .path("/hello") - .request(String.class) - .thenAccept(s -> assertThat(s, is("Public Hello!!"))) - .toCompletableFuture() - .get(); - - webClient.get() - .uri("http://localhost:" + privatePort) - .path("/private/hello") - .request(String.class) - .thenAccept(s -> assertThat(s, is("Private Hello!!"))) - .toCompletableFuture() - .get(); - } - - private static class Params { - int port; - String path; - Http.Status httpStatus; - - private Params(int port, String path, Http.Status httpStatus) { - this.port = port; - this.path = path; - this.httpStatus = httpStatus; - } - - @Override - public String toString() { - return port + ":" + path + " should return " + httpStatus; - } - } - -} diff --git a/examples/webserver/multiport/src/test/resources/application-test.yaml b/examples/webserver/multiport/src/test/resources/application-test.yaml deleted file mode 100644 index d7a80acca0b..00000000000 --- a/examples/webserver/multiport/src/test/resources/application-test.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -server: - port: 0 - host: "localhost" - sockets: - - name: "private" - port: 0 - bind-address: "localhost" - - name: "admin" - port: 0 - bind-address: "localhost" diff --git a/examples/webserver/mutual-tls/README.md b/examples/webserver/mutual-tls/README.md deleted file mode 100644 index a1a1c6cee23..00000000000 --- a/examples/webserver/mutual-tls/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Mutual TLS Example - -This application demonstrates use of client certificates to -authenticate HTTP client. - -## Build and run - -This example requires two components - the server and the client. - -For each, there is an example using configuration, and an example using -builder APIs. - -To test the example: -Start one of - - `ServerBuilderMain` - main class for WebServer using builders - - `ServerConfigMain` - main class for WebServer using Config - -Once the server is running, use one of: - - `ClientBuilderMain` - main class for WebClient using builders - - `ClientConfigMain` - main class for WebClient using Config - -to invoke the endpoint using client certificate. - -Alternative approach is to install the private key and certificate -to your browser and invoke the endpoint manually. - \ No newline at end of file diff --git a/examples/webserver/mutual-tls/automatic-store-generator.sh b/examples/webserver/mutual-tls/automatic-store-generator.sh deleted file mode 100644 index e40ccfe94ab..00000000000 --- a/examples/webserver/mutual-tls/automatic-store-generator.sh +++ /dev/null @@ -1,163 +0,0 @@ -#!/bin/bash -e -# -# 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. -# - -# Windows Mingwin fix for path resolving -#export MSYS_NO_PATHCONV=1 - -NAME="" -TYPE=PKCS12 -SINGLE=true - -createCertificatesAndStores() { - mkdir out - echo 'Generating new key stores...' - keytool -genkeypair -keyalg RSA -keysize 2048 -alias root-ca -dname "CN=$NAME-CA" -validity 21650 -keystore ca.jks -storepass password -keypass password -deststoretype pkcs12 -ext KeyUsage=digitalSignature,keyEncipherment,keyCertSign -ext ExtendedKeyUsage=serverAuth,clientAuth -ext BasicConstraints=ca:true,PathLen:3 - keytool -genkeypair -keyalg RSA -keysize 2048 -alias server -dname "CN=localhost" -validity 21650 -keystore server.jks -storepass password -keypass password -deststoretype pkcs12 - keytool -genkeypair -keyalg RSA -keysize 2048 -alias client -dname "C=CZ,CN=$NAME-client,OU=Prague,O=Oracle" -validity 21650 -keystore client.jks -storepass password -keypass password -deststoretype pkcs12 - echo 'Obtaining client and server certificates...' - keytool -exportcert -keystore client.jks -storepass password -alias client -rfc -file client.cer - keytool -exportcert -keystore server.jks -storepass password -alias server -rfc -file server.cer - echo 'Generating CSR for client and server...' - keytool -certreq -keystore server.jks -alias server -keypass password -storepass password -keyalg rsa -file server.csr - keytool -certreq -keystore client.jks -alias client -keypass password -storepass password -keyalg rsa -file client.csr - echo 'Obtaining CA pem and key...' - keytool -importkeystore -srckeystore ca.jks -destkeystore ca.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass password -deststorepass password - openssl pkcs12 -in ca.p12 -out ca.key -nocerts -passin pass:password -passout pass:password - openssl pkcs12 -in ca.p12 -out ca.pem -nokeys -passin pass:password -passout pass:password - echo 'Signing client and server certificates...' - openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client-signed.cer -days 21650 -passin pass:password - openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out server-signed.cer -sha256 -days 21650 -passin pass:password - echo 'Replacing server and client certificates with the signed ones...' - keytool -importkeystore -srckeystore client.jks -destkeystore client.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass password -deststorepass password - openssl pkcs12 -in client.p12 -nodes -out client-private.key -nocerts -passin pass:password - openssl pkcs12 -export -in client-signed.cer -inkey client-private.key -out client-signed.p12 -name client -passout pass:password - keytool -delete -alias client -keystore client.jks -storepass password - keytool -importkeystore -srckeystore client-signed.p12 -srcstoretype PKCS12 -destkeystore client.jks -srcstorepass password -deststorepass password - keytool -importkeystore -srckeystore server.jks -destkeystore server.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass password -deststorepass password - openssl pkcs12 -in server.p12 -nodes -out server-private.key -nocerts -passin pass:password - openssl pkcs12 -export -in server-signed.cer -inkey server-private.key -out server-signed.p12 -name server -passout pass:password - keytool -delete -alias server -keystore server.jks -storepass password - keytool -importkeystore -srckeystore server-signed.p12 -srcstoretype PKCS12 -destkeystore server.jks -srcstorepass password -deststorepass password - - echo "Importing CA cert to the client and server stores..." - if [ "$SINGLE" = true ] ; then - keytool -v -trustcacerts -keystore client.jks -importcert -file ca.pem -alias root-ca -storepass password -noprompt - keytool -v -trustcacerts -keystore server.jks -importcert -file ca.pem -alias root-ca -storepass password -noprompt - else - keytool -v -trustcacerts -keystore client-truststore.jks -importcert -file ca.pem -alias root-ca -storepass password -noprompt - keytool -v -trustcacerts -keystore server-truststore.jks -importcert -file ca.pem -alias root-ca -storepass password -noprompt - fi - - echo "Changing aliases to 1..." - keytool -changealias -alias server -destalias 1 -keypass password -keystore server.jks -storepass password - keytool -changealias -alias client -destalias 1 -keypass password -keystore client.jks -storepass password - - echo "Generating requested type of stores..." - if [ "$TYPE" = PKCS12 ] || [ "$TYPE" = P12 ] ; then - keytool -importkeystore -srckeystore client.jks -destkeystore out/client.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password -deststorepass password - keytool -importkeystore -srckeystore server.jks -destkeystore out/server.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password -deststorepass password - if [ "$SINGLE" = false ] ; then - keytool -importkeystore -srckeystore server-truststore.jks -destkeystore out/server-truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password -deststorepass password - keytool -importkeystore -srckeystore client-truststore.jks -destkeystore out/client-truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password -deststorepass password - fi - else - mv client.jks out/client.jks - mv server.jks out/server.jks - if [ "$SINGLE" = false ] ; then - mv client-truststore.jks out/client-truststore.jks - mv server-truststore.jks out/server-truststore.jks - fi - fi -} - -removeAllPreviouslyCreatedStores() { - echo 'Removing all of previously created items...' - - rm -fv ca.key - rm -fv ca.jks - rm -fv ca.p12 - rm -fv ca.pem - rm -fv ca.srl - rm -fv server.jks - rm -fv server.cer - rm -fv server.csr - rm -fv server.p12 - rm -fv server-private.key - rm -fv server-signed.cer - rm -fv server-signed.p12 - rm -fv server-truststore.jks - rm -fv client.cer - rm -fv client.csr - rm -fv client.p12 - rm -fv client-private.key - rm -fv client-signed.cer - rm -fv client-signed.p12 - rm -fv client.jks - rm -fv client-truststore.jks - rm -rf out - - echo 'Clean up finished' -} - -while [ "$1" != "" ]; do - case $1 in - -n | --name ) shift - NAME=$1 - ;; - -t | --type ) shift - TYPE=$1 - ;; - -s | --single ) shift - SINGLE=$1 - ;; - -h | --help ) echo "Some cool help" - exit - ;; - * ) echo "ERROR: Invalid parameter" $1 - exit 1 - esac - shift -done -if [ -z "$NAME" ]; then - echo "ERROR: Please specify the name of Organization/Application by parameter -n | --name" - exit 1 -else - echo "Generating certs for Organization/Application "$NAME -fi -case $TYPE in - JKS | P12 | PKCS12 ) - echo "Output file will be of type" $TYPE - ;; - *) - echo 'ERROR: Invalid output type' $TYPE - echo 'Only JKS | P12 | PKCS12 supported' - return 1 -esac -case $SINGLE in - true ) - echo "Truststore and private key will be in single file" - ;; - false ) - echo "Truststore and private key will be in separate files" - ;; - *) - echo "ERROR: Only value true/false valid in single parameter! Current " $SINGLE - exit 1 -esac - -removeAllPreviouslyCreatedStores -createCertificatesAndStores diff --git a/examples/webserver/mutual-tls/pom.xml b/examples/webserver/mutual-tls/pom.xml deleted file mode 100644 index 6357b378e38..00000000000 --- a/examples/webserver/mutual-tls/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-mutual-tls - Helidon WebServer Examples Mutual TLS - - - Application demonstrates the use of mutual TLS with WebServer and WebClient - - - - io.helidon.webserver.examples.mtls.ServerConfigMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webclient - helidon-webclient - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientBuilderMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientBuilderMain.java deleted file mode 100644 index 02b2d978f08..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientBuilderMain.java +++ /dev/null @@ -1,83 +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.webserver.examples.mtls; - -import io.helidon.common.configurable.Resource; -import io.helidon.common.pki.KeyConfig; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientTls; - -/** - * Setting up {@link WebClient} to support mutual TLS via builder. - */ -public class ClientBuilderMain { - - private ClientBuilderMain() { - } - - /** - * Start the example. - * This example executes two requests by Helidon {@link WebClient} which are configured - * by the {@link WebClient.Builder}. - * - * You have to execute either {@link ServerBuilderMain} or {@link ServerConfigMain} for this to work. - * - * If any of the ports has been changed, you have to update ports in this main method also. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - WebClient webClient = createWebClient(); - - System.out.println("Contacting unsecured endpoint!"); - System.out.println("Response: " + callUnsecured(webClient, 8080)); - - System.out.println("Contacting secured endpoint!"); - System.out.println("Response: " + callSecured(webClient, 443)); - - } - - static WebClient createWebClient() { - KeyConfig keyConfig = KeyConfig.keystoreBuilder() - .trustStore() - .keystore(Resource.create("client.p12")) - .keystorePassphrase("password") - .build(); - return WebClient.builder() - .tls(WebClientTls.builder() - .certificateTrustStore(keyConfig) - .clientKeyStore(keyConfig) - .build()) - .build(); - } - - static String callUnsecured(WebClient webClient, int port) { - return webClient.get() - .uri("http://localhost:" + port) - .request(String.class) - .await(); - } - - static String callSecured(WebClient webClient, int port) { - return webClient.get() - .uri("https://localhost:" + port) - .request(String.class) - .await(); - } - - - -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientConfigMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientConfigMain.java deleted file mode 100644 index 84e686bf600..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ClientConfigMain.java +++ /dev/null @@ -1,68 +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.webserver.examples.mtls; - -import io.helidon.config.Config; -import io.helidon.webclient.WebClient; - -/** - * Setting up {@link WebClient} to support mutual TLS via configuration. - */ -public class ClientConfigMain { - - private ClientConfigMain() { - } - - /** - * Start the example. - * This example executes two requests by Helidon {@link WebClient} which are configured - * by the configuration. - * - * You have to execute either {@link ServerBuilderMain} or {@link ServerConfigMain} for this to work. - * - * If any of the ports has been changed, you have to update ports in this main method also. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - Config config = Config.create(); - WebClient webClient = WebClient.create(config.get("client")); - - System.out.println("Contacting unsecured endpoint!"); - System.out.println("Response: " + callUnsecured(webClient, 8080)); - - System.out.println("Contacting secured endpoint!"); - System.out.println("Response: " + callSecured(webClient, 443)); - - } - - static String callUnsecured(WebClient webClient, int port) { - return webClient.get() - .uri("http://localhost:" + port) - .request(String.class) - .await(); - } - - static String callSecured(WebClient webClient, int port) { - return webClient.get() - .uri("https://localhost:" + port) - .request(String.class) - .await(); - } - - - -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerBuilderMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerBuilderMain.java deleted file mode 100644 index c225c057c50..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerBuilderMain.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.webserver.examples.mtls; - -import io.helidon.common.configurable.Resource; -import io.helidon.common.http.Http; -import io.helidon.common.pki.KeyConfig; -import io.helidon.common.reactive.Single; -import io.helidon.webserver.ClientAuthentication; -import io.helidon.webserver.Routing; -import io.helidon.webserver.SocketConfiguration; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerTls; - -/** - * Setting up {@link WebServer} to support mutual TLS via builder. - */ -public class ServerBuilderMain { - - private ServerBuilderMain() { - } - - /** - * Start the example. - * This will start Helidon {@link WebServer} which is configured by the {@link WebServer.Builder}. - * There will be two sockets running: - *

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

    - * Both of the ports mentioned above are default ports for this example and can be changed by updating - * values in this method. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - startServer(8080, 443); - } - - static Single startServer(int unsecured, int secured) { - SocketConfiguration socketConf = SocketConfiguration.builder() - .name("secured") - .port(secured) - .tls(tlsConfig()) - .build(); - Single webServer = WebServer.builder() - .port(unsecured) - .routing(createPlainRouting()) - .addSocket(socketConf, createMtlsRouting()) - .build() - .start(); - - webServer.thenAccept(ws -> { - System.out.println("WebServer is up!"); - System.out.println("Unsecured: http://localhost:" + ws.port() + "/"); - System.out.println("Secured: https://localhost:" + ws.port("secured") + "/"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - return webServer; - } - - private static WebServerTls tlsConfig() { - KeyConfig keyConfig = KeyConfig.keystoreBuilder() - .trustStore() - .keystore(Resource.create("server.p12")) - .keystorePassphrase("password") - .build(); - return WebServerTls.builder() - .clientAuth(ClientAuthentication.REQUIRE) - .trust(keyConfig) - .privateKey(keyConfig) - .build(); - } - - private static Routing createPlainRouting() { - return Routing.builder() - .get("/", (req, res) -> res.send("Hello world unsecured!")) - .build(); - } - - private static Routing createMtlsRouting() { - return Routing.builder() - .get("/", (req, res) -> { - String cn = req.headers().first(Http.Header.X_HELIDON_CN).orElse("Unknown CN"); - res.send("Hello " + cn + "!"); - }) - .build(); - } - -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerConfigMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerConfigMain.java deleted file mode 100644 index da62e94413e..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/ServerConfigMain.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.webserver.examples.mtls; - -import io.helidon.common.http.Http; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Setting up {@link WebServer} to support mutual TLS via configuration. - */ -public class ServerConfigMain { - - private ServerConfigMain() { - } - - /** - * Start the example. - * This will start Helidon {@link WebServer} which is configured by the configuration. - * There will be two sockets running: - *

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

    - * Both of the ports mentioned above are default ports for this example and can be changed via configuration file. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - Config config = Config.create(); - startServer(config.get("server")); - } - - static Single startServer(Config config) { - Single webServer = WebServer.builder(createPlainRouting()) - .config(config) - .addNamedRouting("secured", createMtlsRouting()) - .build() - .start(); - - webServer.thenAccept(ws -> { - System.out.println("WebServer is up!"); - System.out.println("Unsecured: http://localhost:" + ws.port() + "/"); - System.out.println("Secured: https://localhost:" + ws.port("secured") + "/"); - ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionally(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - return null; - }); - return webServer; - } - - private static Routing createPlainRouting() { - return Routing.builder() - .get("/", (req, res) -> res.send("Hello world unsecured!")) - .build(); - } - - private static Routing createMtlsRouting() { - return Routing.builder() - .get("/", (req, res) -> { - String cn = req.headers().first(Http.Header.X_HELIDON_CN).orElse("Unknown CN"); - res.send("Hello " + cn + "!"); - }) - .build(); - } - -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/package-info.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/package-info.java deleted file mode 100644 index 76a5442f3af..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/webserver/examples/mtls/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of mutual TLS configuration for {@link io.helidon.webserver.WebServer} and {@link io.helidon.webclient.WebClient}, - * using both {@link io.helidon.config.Config} and builder based approach. - */ -package io.helidon.webserver.examples.mtls; diff --git a/examples/webserver/mutual-tls/src/main/resources/application.yaml b/examples/webserver/mutual-tls/src/main/resources/application.yaml deleted file mode 100644 index 4f4d4dbb4c1..00000000000 --- a/examples/webserver/mutual-tls/src/main/resources/application.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 8080 - sockets: - - name: "secured" - port: 443 - tls: - client-auth: "REQUIRE" - trust: - keystore: - passphrase: "password" - trust-store: true - resource: - resource-path: "server.p12" - private-key: - keystore: - passphrase: "password" - resource: - resource-path: "server.p12" - -client: - tls: - server: - keystore: - passphrase: "password" - trust-store: true - resource: - resource-path: "client.p12" - client: - keystore: - passphrase: "password" - resource: - resource-path: "client.p12" - diff --git a/examples/webserver/mutual-tls/src/main/resources/client.p12 b/examples/webserver/mutual-tls/src/main/resources/client.p12 deleted file mode 100644 index 4eb3b8325cd0190163032aca86e1d4fc94856822..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4181 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 U@+;F6i_J(6+nRj}N+2@-U-0Veh5!Hn diff --git a/examples/webserver/mutual-tls/src/test/java/io/helidon/webserver/examples/mtls/MutualTlsExampleTest.java b/examples/webserver/mutual-tls/src/test/java/io/helidon/webserver/examples/mtls/MutualTlsExampleTest.java deleted file mode 100644 index 2564bc5b292..00000000000 --- a/examples/webserver/mutual-tls/src/test/java/io/helidon/webserver/examples/mtls/MutualTlsExampleTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.webserver.examples.mtls; - -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Test of mutual TLS example. - */ -public class MutualTlsExampleTest { - - private WebServer webServer; - - @AfterEach - public void killServer() { - if (webServer != null) { - webServer.shutdown() - .await(10, TimeUnit.SECONDS); - } - } - - @Test - public void testConfigAccessSuccessful() { - Config config = Config.just(() -> ConfigSources.classpath("application-test.yaml").build()); - webServer = ServerConfigMain.startServer(config.get("server")).await(); - WebClient webClient = WebClient.create(config.get("client")); - - assertThat(ClientConfigMain.callUnsecured(webClient, webServer.port()), is("Hello world unsecured!")); - assertThat(ClientConfigMain.callSecured(webClient, webServer.port("secured")), is("Hello Helidon-client!")); - } - - @Test - public void testBuilderAccessSuccessful() { - webServer = ServerBuilderMain.startServer(-1, -1).await(); - WebClient webClient = ClientBuilderMain.createWebClient(); - - assertThat(ClientBuilderMain.callUnsecured(webClient, webServer.port()), is("Hello world unsecured!")); - assertThat(ClientBuilderMain.callSecured(webClient, webServer.port("secured")), is("Hello Helidon-client!")); - } -} \ No newline at end of file diff --git a/examples/webserver/mutual-tls/src/test/resources/application-test.yaml b/examples/webserver/mutual-tls/src/test/resources/application-test.yaml deleted file mode 100644 index 651414573dc..00000000000 --- a/examples/webserver/mutual-tls/src/test/resources/application-test.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -server: - port: 0 - sockets: - - name: "secured" - port: 0 - tls: - client-auth: "REQUIRE" - trust: - keystore: - passphrase: "password" - trust-store: true - resource: - resource-path: "server.p12" - private-key: - keystore: - passphrase: "password" - resource: - resource-path: "server.p12" - -client: - tls: - server: - keystore: - passphrase: "password" - trust-store: true - resource: - resource-path: "client.p12" - client: - keystore: - passphrase: "password" - resource: - resource-path: "client.p12" - diff --git a/examples/webserver/opentracing/Dockerfile b/examples/webserver/opentracing/Dockerfile deleted file mode 100644 index dccd442f15b..00000000000 --- a/examples/webserver/opentracing/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# 1st stage, build the app -FROM maven:3.6.3-openjdk-17-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:17-jdk-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-webserver-opentracing.jar ./ -COPY --from=build /helidon/target/libs ./libs - -ENV tracing.host="zipkin" - -CMD ["java", "-jar", "helidon-examples-webserver-opentracing.jar"] - -EXPOSE 8080 diff --git a/examples/webserver/opentracing/README.md b/examples/webserver/opentracing/README.md deleted file mode 100644 index f5ffcce5875..00000000000 --- a/examples/webserver/opentracing/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Opentracing Example Application - -## Start Zipkin - -With Docker: -```bash -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -``` - -With Java 8+: -```bash -curl -sSL https://zipkin.io/quickstart.sh | bash -s -java -jar zipkin.jar -``` - -## Build and run - -With Docker: -```bash -docker build -t helidon-webserver-opentracing-example . -docker run --rm -d --link zipkin --name helidon-webserver-opentracing-example \ - -p 8080:8080 helidon-webserver-opentracing-example:latest -``` - -With Java 8+: -```bash -mvn package -java -jar target/helidon-examples-webserver-opentracing.jar -``` - -Try the endpoint: -```bash -curl http://localhost:8080/test -``` - -Then check out the traces at http://localhost:9411. - -Stop the docker containers: -```bash -docker stop zipkin helidon-webserver-opentracing-example -``` diff --git a/examples/webserver/opentracing/pom.xml b/examples/webserver/opentracing/pom.xml deleted file mode 100644 index 5a8bd04fcde..00000000000 --- a/examples/webserver/opentracing/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-opentracing - Helidon WebServer Examples OpenTracing - - - An example app with Open Tracing support. - - - - io.helidon.webserver.examples.opentracing.Main - 2.23.4 - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-jersey - - - io.helidon.tracing - helidon-tracing-zipkin - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - org.mockito - mockito-core - ${version.lib.mockito} - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/Main.java b/examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/Main.java deleted file mode 100644 index 6d8f0ad4a24..00000000000 --- a/examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/Main.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2017, 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.webserver.examples.opentracing; - -import io.helidon.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The ZipkinExampleMain is an app that leverages a use of Open Tracing and sends - * the collected data to Zipkin. - * - * @see io.helidon.tracing.TracerBuilder - * @see io.helidon.tracing.zipkin.ZipkinTracerBuilder - */ -public final class Main { - - private Main() { - } - - /** - * Run the OpenTracing application. - * - * @param args not used - */ - public static void main(String[] args) { - - // configure logging in order to not have the standard JVM defaults - LogConfig.configureRuntime(); - - Config config = Config.builder() - .sources(ConfigSources.environmentVariables()) - .build(); - - WebServer webServer = WebServer.builder( - Routing.builder() - .any((req, res) -> { - System.out.println("Received another request."); - req.next(); - }) - .get("/test", (req, res) -> res.send("Hello World!")) - .post("/hello", (req, res) -> { - req.content() - .as(String.class) - .thenAccept(s -> res.send("Hello: " + s)) - .exceptionally(t -> { - req.next(t); - return null; - }); - })) - .port(8080) - .tracer(TracerBuilder.create(config.get("tracing")) - .serviceName("demo-first") - .registerGlobal(true) - .build()) - .build(); - - webServer.start() - .whenComplete((server, throwable) -> { - System.out.println("Started at http://localhost:" + server.port()); - }); - } - -} diff --git a/examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/package-info.java b/examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/package-info.java deleted file mode 100644 index 7590b1253e1..00000000000 --- a/examples/webserver/opentracing/src/main/java/io/helidon/webserver/examples/opentracing/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * An example of WebServer app supporting Open Tracing. - * - * @see io.helidon.webserver.examples.opentracing.ZipkinExampleMain - */ -package io.helidon.webserver.examples.opentracing; diff --git a/examples/webserver/opentracing/src/main/resources/logging.properties b/examples/webserver/opentracing/src/main/resources/logging.properties deleted file mode 100644 index 4833373add0..00000000000 --- a/examples/webserver/opentracing/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -#All attributes details -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -#All log level details -.level=FINEST - -io.helidon.webserver.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/webserver/pom.xml b/examples/webserver/pom.xml deleted file mode 100644 index 7f000b18f8f..00000000000 --- a/examples/webserver/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 3.2.7-SNAPSHOT - - io.helidon.examples.webserver - helidon-examples-webserver-project - Helidon WebServer Examples - pom - - - basics - tutorial - comment-aas - static-content - jersey - opentracing - streaming - websocket - tls - mutual-tls - fault-tolerance - threadpool - multiport - - diff --git a/examples/webserver/static-content/README.md b/examples/webserver/static-content/README.md deleted file mode 100644 index 6b4d1edfd8b..00000000000 --- a/examples/webserver/static-content/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Static Content Example - -This application demonstrates use of the StaticContentSupport to serve static files - together with a simple REST service. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-webserver-static-content.jar -``` - -Open http://localhost:8080 in your browser. diff --git a/examples/webserver/static-content/pom.xml b/examples/webserver/static-content/pom.xml deleted file mode 100644 index a94cf363963..00000000000 --- a/examples/webserver/static-content/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-static-content - Helidon WebServer Examples Static Content - - - Application demonstrates combination of the static content with a simple REST API. It counts accesses and display it - on the WEB page. - - - - io.helidon.webserver.examples.staticcontent.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.media - helidon-media-jsonp - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/CounterService.java b/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/CounterService.java deleted file mode 100644 index 66ba1f8217a..00000000000 --- a/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/CounterService.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.staticcontent; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.LongAdder; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * Counts access to the WEB service. - */ -public class CounterService implements Service { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - private final LongAdder allAccessCounter = new LongAdder(); - private final AtomicInteger apiAccessCounter = new AtomicInteger(); - - @Override - public void update(Routing.Rules routingRules) { - routingRules.any(this::handleAny) - .get("/api/counter", this::handleGet); - } - - private void handleAny(ServerRequest request, ServerResponse response) { - allAccessCounter.increment(); - request.next(); - } - - private void handleGet(ServerRequest request, ServerResponse response) { - int apiAcc = apiAccessCounter.incrementAndGet(); - JsonObject result = JSON.createObjectBuilder() - .add("all", allAccessCounter.longValue()) - .add("api", apiAcc) - .build(); - response.send(result); - } -} diff --git a/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/Main.java b/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/Main.java deleted file mode 100644 index 62eebc9d8db..00000000000 --- a/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/Main.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.staticcontent; - -import io.helidon.common.http.Http; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; - -/** - * Application demonstrates combination of the static content with a simple REST API. It counts accesses and display it - * on the WEB page. - */ -public class Main { - - private Main() { - } - - /** - * Creates new {@link Routing}. - * - * @return the new instance - */ - static Routing createRouting() { - return Routing.builder() - .any("/", (req, res) -> { - // showing the capability to run on any path, and redirecting from root - res.status(Http.Status.MOVED_PERMANENTLY_301); - res.headers().put(Http.Header.LOCATION, "/ui"); - res.send(); - }) - .register("/ui", new CounterService()) - .register("/ui", StaticContentSupport.builder("WEB") - .welcomeFileName("index.html") - .build()) - .build(); - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - WebServer server = WebServer.builder(createRouting()) - .port(8080) - .addMediaSupport(JsonpSupport.create()) - .build(); - - // Start the server and print some info. - server.start().thenAccept(ws -> { - System.out.println("WEB server is up! http://localhost:" + ws.port()); - }); - - // Server threads are not demon. NO need to block. Just react. - server.whenShutdown() - .thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - - } -} diff --git a/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/package-info.java b/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/package-info.java deleted file mode 100644 index 46574a11dc2..00000000000 --- a/examples/webserver/static-content/src/main/java/io/helidon/webserver/examples/staticcontent/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Application demonstrates combination of the static content with a simple REST API. It counts accesses and display it - * on the WEB page. - *

    - * Start with {@link io.helidon.webserver.examples.staticcontent.Main} class. - * - * @see io.helidon.webserver.examples.staticcontent.Main - */ -package io.helidon.webserver.examples.staticcontent; diff --git a/examples/webserver/static-content/src/main/resources/WEB/css/app.css b/examples/webserver/static-content/src/main/resources/WEB/css/app.css deleted file mode 100644 index b990bfb07b1..00000000000 --- a/examples/webserver/static-content/src/main/resources/WEB/css/app.css +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -body { - padding-top: 2rem; -} diff --git a/examples/webserver/static-content/src/main/resources/WEB/index.html b/examples/webserver/static-content/src/main/resources/WEB/index.html deleted file mode 100644 index f75189908b7..00000000000 --- a/examples/webserver/static-content/src/main/resources/WEB/index.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - Static Content Example - - - - - - - -

    - - -
    -
    -

    Hello!

    -

    -
    -
    - -
    - -
    -
    -

    Heading

    -

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

    -

    View details »

    -
    -
    -

    Heading

    -

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

    -

    View details »

    -
    -
    -

    Heading

    -

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

    -

    View details »

    -
    -
    - -
    - -
    -

    © Oracle 2017

    -
    -
    - - - - - - - diff --git a/examples/webserver/static-content/src/main/resources/WEB/js/app.js b/examples/webserver/static-content/src/main/resources/WEB/js/app.js deleted file mode 100644 index b2c8d0b3abd..00000000000 --- a/examples/webserver/static-content/src/main/resources/WEB/js/app.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -$(document).ready(function() { - $.get("api/counter", function (data) { - $("#hello-message").html("This page was reloaded " + data.api + " times. " - + "This WebServer already served " + data.all + " requests."); - }); -}); diff --git a/examples/webserver/streaming/README.md b/examples/webserver/streaming/README.md deleted file mode 100644 index 85085d110a7..00000000000 --- a/examples/webserver/streaming/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Streaming Example - -This application uses NIO and data buffers to show the implementation of a simple streaming service. - Files can be uploaded and downloaded in a streaming fashion using `Subscriber` and -`Producer`. As a result, service runs in constant space instead of proportional -to the size of the file being uploaded or downloaded. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-webserver-streaming.jar -``` - -Upload a file and download it back with `curl`: -```bash -curl --data-binary "@target/classes/large-file.bin" http://localhost:8080/upload -curl http://localhost:8080/download -``` diff --git a/examples/webserver/streaming/pom.xml b/examples/webserver/streaming/pom.xml deleted file mode 100644 index a36858eca1d..00000000000 --- a/examples/webserver/streaming/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-streaming - Helidon WebServer Examples Streaming - - - Application that demonstrates how to write a service that uploads and downloads - a file using chunks, in a streaming manner. - - - - io.helidon.webserver.examples.streaming.Main - - - - - io.helidon.webserver - helidon-webserver - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/Main.java b/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/Main.java deleted file mode 100644 index 3476387f88c..00000000000 --- a/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/Main.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.streaming; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * Class Main. Entry point to streaming application. - */ -public class Main { - - static final String LARGE_FILE_RESOURCE = "/large-file.bin"; - - private Main() { - } - - /** - * Creates new {@link Routing}. - * - * @return the new instance - */ - static Routing createRouting() { - return Routing.builder() - .register(new StreamingService()) - .build(); - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - WebServer server = WebServer.builder(createRouting()) - .port(8080) - .build(); - - server.start().thenAccept(ws -> - System.out.println("Steaming service is up at http://localhost:" + ws.port()) - ); - - server.whenShutdown().thenRun(() -> - System.out.println("Streaming service is down") - ); - } -} diff --git a/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/StreamingService.java b/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/StreamingService.java deleted file mode 100644 index a860564e91a..00000000000 --- a/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/StreamingService.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.streaming; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.channels.ReadableByteChannel; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.concurrent.ScheduledExecutorService; -import java.util.logging.Logger; - -import io.helidon.common.configurable.ScheduledThreadPoolSupplier; -import io.helidon.common.http.DataChunk; -import io.helidon.common.reactive.IoMulti; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import static io.helidon.webserver.examples.streaming.Main.LARGE_FILE_RESOURCE; - -/** - * StreamingService class. Uses a {@code Subscriber} and a - * {@code Publisher} for uploading and downloading files. - */ -public class StreamingService implements Service { - private static final Logger LOGGER = Logger.getLogger(StreamingService.class.getName()); - private final ScheduledExecutorService executor = ScheduledThreadPoolSupplier.create().get(); - private final Path filePath; - - StreamingService() { - URL resource = getClass().getResource(LARGE_FILE_RESOURCE); - if (resource == null) { - throw new IllegalStateException("Resource not found: " + LARGE_FILE_RESOURCE); - } - try { - filePath = Paths.get(resource.toURI()); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - - @Override - public void update(Routing.Rules routingRules) { - routingRules.get("/download", this::download) - .post("/upload", this::upload); - } - - private void upload(ServerRequest request, ServerResponse response) { - LOGGER.info("Entering upload ... " + Thread.currentThread()); - Path tempFilePath = createTempFile("large-file", ".tmp"); - request.content() - .map(DataChunk::data) - .flatMapIterable(Arrays::asList) - .to(IoMulti.writeToFile(tempFilePath) - .executor(executor) - .build()); - LOGGER.info("Exiting upload ..."); - } - - private void download(ServerRequest request, ServerResponse response) { - LOGGER.info("Entering download ..." + Thread.currentThread()); - long length = filePath.toFile().length(); - response.headers().contentLength(length); - response.send(IoMulti.multiFromByteChannelBuilder(newByteChannel(filePath)) - .executor(executor) - .build()); - LOGGER.info("Exiting download ..."); - } - - @SuppressWarnings("SameParameterValue") - private static Path createTempFile(String prefix, String suffix) { - try { - return Files.createTempFile(prefix, suffix); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - private static ReadableByteChannel newByteChannel(Path path) { - try { - return Files.newByteChannel(path); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } -} diff --git a/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/package-info.java b/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/package-info.java deleted file mode 100644 index dfafaac61e3..00000000000 --- a/examples/webserver/streaming/src/main/java/io/helidon/webserver/examples/streaming/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - *

    - * Start with {@link io.helidon.webserver.examples.streaming.Main} class. - * - * @see io.helidon.webserver.examples.streaming.Main - */ -package io.helidon.webserver.examples.streaming; diff --git a/examples/webserver/streaming/src/main/resources/large-file.bin b/examples/webserver/streaming/src/main/resources/large-file.bin deleted file mode 100644 index 909e3e3e9bcc1e7b1993f3f5abd1532a938df436..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeIuF#!Mo0K%a4Pi+kkh(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM Y7%*VKfB^#r3>YwAz<>b*1`NCp3@`uy0RR91 diff --git a/examples/webserver/threadpool/README.md b/examples/webserver/threadpool/README.md deleted file mode 100644 index fbf71967eee..00000000000 --- a/examples/webserver/threadpool/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Helidon WebServer Thread Pool Example - -This example shows how to use an application specific threadpool. - -With the Helidon WebServer you do not want to block the Netty thread that is executing -your Handler. So you either need to use WebServer's reactive APIs: - -``` - request.content().as(JsonObject.class) - .thenAccept(jo -> doSomething(jo, response)) -``` - -Or pass the request off to a thread pool dedicated to your business logic. This -example shows how to do this in `getMessageSlowlyHandler`. - -Helidon's `ThreadPoolSupplier` provides thread pools that automatically propagate -request `Context` so that tracing and authentication information is preserved across -threads. - -You can use the `Context` registry to propagate your own data across threads. You can - also do this by passing the information directly to your `Runnable`. The -example shows both techniques. - -## Configuration - -See `application.yaml` for an example of how you can configure the number of Netty -worker threads, as well as provide a configuration for the dedicated application -threadpool. - -## Build and run - -With JDK11+ -```bash -mvn package -java -jar target/helidon-examples-webserver-threadpool.jar -``` - -When the server starts up you will see it log some information about the application -thread pool. This should reflect what is specified in `application.yaml`. For example: - -``` -2021.03.16 13:50:31 FINE io.helidon.common.configurable.ThreadPool Thread[main,5,main]: ThreadPool 'helidon-thread-pool-2' {corePoolSize=5, maxPoolSize=50, queueCapacity=10000, growthThreshold=1000, growthRate=0%, averageQueueSize=0.00, peakQueueSize=0, averageActiveThreads=0.00, peakPoolSize=0, currentPoolSize=0, completedTasks=0, failedTasks=0, rejectedTasks=0} -``` - -See `logging.properties` for the logging configuration. - -## Exercise the application - -Each request will return the name of the thread the created the response. For example: - -``` -$ curl -X GET http://localhost:8080/greet/Jane -{"message":"Hello Jane!","thread":"Thread[nioEventLoopGroup-3-2,10,main]"} -``` - -`nioEventLoopGroup-` indicates that this is a Netty worker thread. To exercise -the application thread pool do this: - -``` -curl -X GET http://localhost:8080/greet/slowly/Jane -{"message":"Hello Jane!","thread":"Thread[my-thread-1,5,helidon-thread-pool-2]"} -``` - -You'll notice that the response takes ~3 seconds to return -- that's an artificial delay -we have in our handler. Also note that the thread name starts with `my-thread-`. That indicates -this is a thread from the dedicated application thread pool. - diff --git a/examples/webserver/threadpool/pom.xml b/examples/webserver/threadpool/pom.xml deleted file mode 100644 index adfaa13cb34..00000000000 --- a/examples/webserver/threadpool/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-threadpool - Helidon WebServer Examples Thread Pools - - - io.helidon.examples.webserver.threadpool.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.media - helidon-media-jsonp - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-service-api - - - io.helidon.metrics - helidon-metrics - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/GreetService.java b/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/GreetService.java deleted file mode 100644 index 68e494a46cb..00000000000 --- a/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/GreetService.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.webserver.threadpool; - -import java.util.Collections; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.configurable.ThreadPoolSupplier; -import io.helidon.common.context.Contexts; -import io.helidon.common.http.Http; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:8080/greet/Joe - * - * Change greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting - * - * The message is returned as a JSON object - */ - -public class GreetService implements Service { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); - - private static ExecutorService myThreadPool; - - GreetService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - - // Build a thread pool using the configuration - myThreadPool = ThreadPoolSupplier.builder().config(config.get("application-thread-pool")).build().get(); - } - - /** - * A service registers itself by updating the routing rules. - * @param rules the routing rules. - */ - @Override - public void update(Routing.Rules rules) { - rules - .get("/", this::getDefaultMessageHandler) - .get("/slowly/{name}", this::getMessageSlowlyHandler) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { - sendResponse(response, "World"); - } - - /** - * Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageHandler(ServerRequest request, ServerResponse response) { - String name = request.path().param("name"); - sendResponse(response, name); - } - - /** - * Slowly Return a greeting message using the name that was provided. - * @param request the server request - * @param response the server response - */ - private void getMessageSlowlyHandler(ServerRequest request, ServerResponse response) { - - String name = request.path().param("name"); - - // One way to pass data to new thread is to use Context - request.context().register("NAME_PARAM", name + "_from_context"); - - // Another way, just pass via Runnable. - myThreadPool.submit(() -> sendResponseSlowly(response, name, 3)); - } - - /** - * Send a response slowly. This simulates blocking business logic. - * - * @param response server response - * @param name name to greet - * @param sleepSeconds artificial delay to simulate blocking business logic - */ - private void sendResponseSlowly(ServerResponse response, String name, int sleepSeconds) { - - // Fetch NAME_PARAM from Context - String nameFromContext = Contexts.context() - .flatMap(ctx -> ctx.get("NAME_PARAM", String.class)) - .orElseThrow(() -> new IllegalStateException("No NAME_PARAM in current context")); - - LOGGER.info("Name from method parameter: " + name + ". Name from context: " + nameFromContext); - - // Simulate blocking business logic - try { - Thread.sleep(sleepSeconds * 1000); - } catch (InterruptedException ex) { } - - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - LOGGER.info("Response sent by thread " + Thread.currentThread().toString()); - - String msg = String.format("%s %s!", greeting.get(), name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .add("thread", Thread.currentThread().toString()) - .build(); - response.send(returnObject); - } - - private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - - if (ex.getCause() instanceof JsonException){ - - LOGGER.log(Level.FINE, "Invalid JSON", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Invalid JSON") - .build(); - response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); - } else { - - LOGGER.log(Level.FINE, "Internal error", ex); - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "Internal error") - .build(); - response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); - } - - return null; - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Http.Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Http.Status.NO_CONTENT_204).send(); - } - - /** - * Set the greeting to use in future messages. - * @param request the server request - * @param response the server response - */ - private void updateGreetingHandler(ServerRequest request, - ServerResponse response) { - request.content().as(JsonObject.class) - .thenAccept(jo -> updateGreetingFromJson(jo, response)) - .exceptionally(ex -> processErrors(ex, request, response)); - } -} diff --git a/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/Main.java b/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/Main.java deleted file mode 100644 index 0692c2fb235..00000000000 --- a/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/Main.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.webserver.threadpool; - -import io.helidon.common.LogConfig; -import io.helidon.common.reactive.Single; -import io.helidon.config.Config; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.serviceapi.MetricsSupport; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(final String[] args) { - // By default this will pick up application.yaml from the classpath - Config config = Config.create(); - startServer(config); - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - */ - static Single startServer(Config config) { - // load logging configuration - LogConfig.configureRuntime(); - - // Build server using three ports: - // default public port, admin port, private port - WebServer server = WebServer.builder(createPublicRouting(config)) - .config(config.get("server")) - .addMediaSupport(JsonpSupport.create()) - .build(); - - Single webServerSingle = server.start(); - - // Try to start the server. If successful, print some info and arrange to - // print a message at shutdown. If unsuccessful, print the exception. - webServerSingle - .thenAccept(ws -> { - System.out.println( - "WEB server is up! http://localhost:" + ws.port()); - ws.whenShutdown().thenRun(() - -> System.out.println("WEB server is DOWN. Good bye!")); - }) - .exceptionallyAccept(t -> { - System.err.println("Startup failed: " + t.getMessage()); - t.printStackTrace(System.err); - }); - - // Server threads are not daemon. No need to block. Just react. - - return webServerSingle; - } - - /** - * Creates public {@link Routing}. - * - * @return routing for use on "public" port - */ - private static Routing createPublicRouting(Config config) { - MetricsSupport metrics = MetricsSupport.create(); - HealthSupport health = HealthSupport.builder() - .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks - .build(); - GreetService greetService = new GreetService(config); - return Routing.builder() - .register(health) - .register(metrics) - .register("/greet", greetService) - .build(); - } - -} diff --git a/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/package-info.java b/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/package-info.java deleted file mode 100644 index 2bead4ad652..00000000000 --- a/examples/webserver/threadpool/src/main/java/io/helidon/examples/webserver/threadpool/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Application that exposes multiple ports. - */ -package io.helidon.examples.webserver.threadpool; diff --git a/examples/webserver/threadpool/src/main/resources/application.yaml b/examples/webserver/threadpool/src/main/resources/application.yaml deleted file mode 100644 index 0218743dc24..00000000000 --- a/examples/webserver/threadpool/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -server: - port: 8080 - host: "localhost" - # This controls the size of the Netty worker thread pool - worker-count: 10 - -app: - greeting: "Hello" - -# Configuration for the application thread pool. For config options see -# ThreadPoolSupplier.Builder.config() -application-thread-pool: - thread-name-prefix: "my-thread-" - core-pool-size: 5 \ No newline at end of file diff --git a/examples/webserver/threadpool/src/main/resources/logging.properties b/examples/webserver/threadpool/src/main/resources/logging.properties deleted file mode 100644 index e5b54190393..00000000000 --- a/examples/webserver/threadpool/src/main/resources/logging.properties +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -# Increase ThreadPool logging so we can see what values are used -# to create the application ThreadPool -io.helidon.common.configurable.ThreadPool.level=FINE - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO diff --git a/examples/webserver/threadpool/src/test/java/io/helidon/examples/webserver/threadpool/MainTest.java b/examples/webserver/threadpool/src/test/java/io/helidon/examples/webserver/threadpool/MainTest.java deleted file mode 100644 index 4b9cc4ec70c..00000000000 --- a/examples/webserver/threadpool/src/test/java/io/helidon/examples/webserver/threadpool/MainTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.examples.webserver.threadpool; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -public class MainTest { - - private static WebServer webServer; - private static WebClient webClient; - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - - static { - TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - @BeforeAll - public static void startTheServer() { - - // Use test configuration so we can have ports allocated dynamically - Config config = Config.builder().addSource(ConfigSources.classpath("application-test.yaml")).build(); - - webServer = Main.startServer(config).await(); - webClient = WebClient.builder() - .baseUri("http://localhost:" + webServer.port()) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - @AfterAll - public static void stopServer() { - if (webServer != null) { - webServer.shutdown().await(10, TimeUnit.SECONDS); - } - } - - @Test - public void testHelloWorld() { - - JsonObject jsonObject; - WebClientResponse response; - - jsonObject = webClient.get() - .path("/greet") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello World!")); - - jsonObject = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(jsonObject.getString("message"), is("Hello Joe!")); - - WebClientResponse res = webClient.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT) - .await(); - assertThat(res.status().code(), is(204)); - - JsonObject json = webClient.get() - .path("/greet/Joe") - .request(JsonObject.class) - .await(); - assertThat(json.getString("message"), is("Hola Joe!")); - - response = webClient.get() - .path("/health") - .request() - .await(); - assertThat(response.status().code(), is(200)); - - response = webClient.get() - .path("/metrics") - .request() - .await(); - assertThat(response.status().code(), is(200)); - } - -} diff --git a/examples/webserver/threadpool/src/test/resources/application-test.yaml b/examples/webserver/threadpool/src/test/resources/application-test.yaml deleted file mode 100644 index a06dc3469f9..00000000000 --- a/examples/webserver/threadpool/src/test/resources/application-test.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -server: - port: 0 - host: "localhost" - # This controls the size of the Netty worker thread pool - worker-count: 10 - -app: - greeting: "Hello" - -# Configuration for the application thread pool. For config options see -# ThreadPoolSupplier.Builder.config() -application-thread-pool: - thread-name-prefix: "my-thread-" - core-pool-size: 5 diff --git a/examples/webserver/tls/pom.xml b/examples/webserver/tls/pom.xml deleted file mode 100644 index 6017598fe20..00000000000 --- a/examples/webserver/tls/pom.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-tls - Helidon WebServer Examples TLS - - - Application demonstrates TLS configuration using a builder - and config. - - - - io.helidon.webserver.examples.tls.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webclient - helidon-webclient - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-params - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/Main.java b/examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/Main.java deleted file mode 100644 index fe7f446dfe4..00000000000 --- a/examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/Main.java +++ /dev/null @@ -1,84 +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.webserver.examples.tls; - -import java.util.concurrent.CompletionStage; - -import io.helidon.common.LogConfig; -import io.helidon.common.configurable.Resource; -import io.helidon.common.pki.KeyConfig; -import io.helidon.config.Config; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerTls; - -/** - * Main class of TLS example. - */ -public final class Main { - // utility class - private Main() { - } - - /** - * Start the example. - * This will start two Helidon WebServers, both protected by TLS - one configured from config, one using a builder. - * Port of the servers will be configured from config, to be able to switch to an ephemeral port for tests. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Config config = Config.create(); - startConfigBasedServer(config.get("config-based")) - .thenAccept(ws -> { - System.out.println("Started config based WebServer on http://localhost:" + ws.port()); - }); - startBuilderBasedServer(config.get("builder-based")) - .thenAccept(ws -> { - System.out.println("Started builder based WebServer on http://localhost:" + ws.port()); - }); - } - - static CompletionStage startBuilderBasedServer(Config config) { - return WebServer.builder() - .config(config) - .routing(routing()) - // now let's configure TLS - .tls(WebServerTls.builder() - .privateKey(KeyConfig.keystoreBuilder() - .keystore(Resource.create("certificate.p12")) - .keystorePassphrase("helidon"))) - .build() - .start(); - } - - static CompletionStage startConfigBasedServer(Config config) { - return WebServer.builder() - .config(config) - .routing(routing()) - .build() - .start(); - } - - private static Routing routing() { - return Routing.builder() - .get("/", (req, res) -> res.send("Hello!")) - .build(); - } -} diff --git a/examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/package-info.java b/examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/package-info.java deleted file mode 100644 index 3654cebdb8c..00000000000 --- a/examples/webserver/tls/src/main/java/io/helidon/webserver/examples/tls/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Example of TLS configuration for webserver, using both {@link io.helidon.config.Config} and builder based approach. - */ -package io.helidon.webserver.examples.tls; diff --git a/examples/webserver/tls/src/main/resources/application.yaml b/examples/webserver/tls/src/main/resources/application.yaml deleted file mode 100644 index a10b3d4da39..00000000000 --- a/examples/webserver/tls/src/main/resources/application.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -config-based: - port: 8080 - tls: - private-key.keystore: - resource.resource-path: "certificate.p12" - passphrase: "helidon" - -builder-based: - port: 8081 diff --git a/examples/webserver/tls/src/main/resources/certificate.p12 b/examples/webserver/tls/src/main/resources/certificate.p12 deleted file mode 100644 index b2cb83427d181db6657cca1e2a70fa49bdb40724..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2557 zcmY+^XEYm(8V7JmlMo{{TD7XS(rOdCqP1$YQbmkLgBGnF^QB0TP=wG}txZtlidCDw z)Sgw;=+!}s+9TAauJ@dK?|biu=RD{9|Ic|o{@^6&J`ivQPJ*^Tpt2DL5xX1!W8EiKoCLD{yMpA9K*pyL3J732UAlia0Jso@_1_=Z0T4J0#L{lBIEeZUWB`FI zOrazYpZuRyYsv6BeHC3~j`v3#2BuL54sF9g33lb7P}vO z^L@D&e_lq+R~&%SWhKN}ToPOtb0wP*>tMq!MR%LPxC|K2vexVZw7r)tDy)%eaTb(e zymOPI@|`_zsjBfH>KrDoY|{2>*SPVb9)3${`ioIt&lD^n1>aYJX@9jkH^NI+awU6I z5}VJ{XIl=ZcR5fqD1=dIRnSa2hXA4mPHb`**VNljMuahqhyWgC(dV1W_O{Xesk6?G|Hm} z%Ymzi5}iSx=2=rL!=M>3gKhYPO`Z(?mHSQ4hN;QSTNpTQ@_TZ?aEG2+(ZXTfydo-W6D);8#bFnW=!`VB|wJ~Lq;7IJt7k3!}g=a*lC4oPuToq z&>)ev0`D1~><0p6rOuR)8)meX01i{$W%pZFO!9`EsMYX?*za9eE-fy+0R?mEbZ?^V zzFc+fAgPl9G2L#jNiKc|5(PfYLm!q8+{>?(!{wqB78A|~5{jft$eF3V$U}(5yXB*` z<%0Ke9m{xQZUtG6@h7lib5ZWupm{+>{kp+Nqc$=+`C-ga3sm7%RHDVv=7|t;mF_7cPQllGD~yp+gV@JWi%@eQ^%O^yJEK0h!-ub zGR|wLJT*gDg2F}~2LIYcd`2&YyZ`VNZd$(dWaKE!5!GN?0{?THI@7p|Bci`PWPdhQ zJW--7*qsX}fwlezk{l9P9z+6PJB?*eM+(CBA68faz*B$LPT^VlKW)zZrHx7dM`xnW zz39KR0g*sGsZ9x^4W$E^JyaaJHlxD|v*I(~%85iIo_qP~!SHk8RNFkAUW<41n}+0r z#G78z*XPpj9C=;rI>Jg@J^Ojv#XJk}`0<_l6|}towM8=4Da!sjMYma}Q%f@;W=XKNb}azh zM@r2j*j32(O*x3HOxA=&L zYqyUN0s=%oMLLL=24t=}e@ypZ9?=*>sW<~`b4gMs$_mZU1BI?mZ;j$M!X5dGc$G&_ z%TlAZAq3I+6)Tx&m_mC`6b>b^*b%I|z5nK#!x z4=+8DC9#xuoyD7=UfF_f2dSUY69uw{LG3@ojC#@hRpxBNYLm2j=%5+-GB>9DT5-mo zlGWbm?0JQ#H|clJi^+Vk(uco~=mDF>G7TyGa@Q zwbh%8M?s6PG?>J{ot?-rkbBPMa9aW1@caj=?))-nN2G42~VPe?;x^u`J>Z__NtPR;PKNmTxJRZsRjHmS_HQgytm6aEgg`HWhYDmA#*m6f-}X9eY7|M|2=H|)_IgcA0W-c$R{g^9VCk`@mH{y$X547S z!rUXh(4yZNfl5o1iCga@P#q`H-ymx~c19ICpiQ>;g%+##uN9o0i|B&NxZTSg@o#1J z%F=B#*OwHWkJs;-UTYZl6(ouzu5m@wHIAB7{}qHrh#dh@-oPiJ!{8N_1W OY0p~c!p8BJlK%o#WVn_9 diff --git a/examples/webserver/tls/src/main/resources/logging.properties b/examples/webserver/tls/src/main/resources/logging.properties deleted file mode 100644 index 24de00b0293..00000000000 --- a/examples/webserver/tls/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.server.level=INFO diff --git a/examples/webserver/tls/src/test/java/io/helidon/webserver/examples/tls/MainTest.java b/examples/webserver/tls/src/test/java/io/helidon/webserver/examples/tls/MainTest.java deleted file mode 100644 index 01ac297c36c..00000000000 --- a/examples/webserver/tls/src/test/java/io/helidon/webserver/examples/tls/MainTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.tls; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.stream.Stream; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.webclient.WebClient; -import io.helidon.webclient.WebClientTls; -import io.helidon.webserver.WebServer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -class MainTest { - private static WebServer configBasedServer; - private static WebServer builderBasedServer; - private static WebClient configBasedClient; - private static WebClient builderBasedClient; - - @BeforeAll - static void initClass() throws ExecutionException, InterruptedException { - Config config = Config.create(ConfigSources.classpath("test-application.yaml"), - ConfigSources.classpath("application.yaml")); - - configBasedServer = Main.startConfigBasedServer(config.get("config-based")) - .toCompletableFuture() - .get(); - builderBasedServer = Main.startBuilderBasedServer(config.get("builder-based")) - .toCompletableFuture() - .get(); - - configBasedClient = WebClient.builder() - .baseUri("https://localhost:" + configBasedServer.port()) - // trust all, as we use a self-signed certificate - .tls(WebClientTls.builder().trustAll(true).build()) - .build(); - - builderBasedClient = WebClient.builder() - .baseUri("https://localhost:" + builderBasedServer.port()) - // trust all, as we use a self-signed certificate - .tls(WebClientTls.builder().trustAll(true).build()) - .build(); - } - - @AfterAll - static void destroyClass() { - CompletionStage configBased; - CompletionStage builderBased; - - if (null == configBasedServer) { - configBased = CompletableFuture.completedFuture(null); - } else { - configBased = configBasedServer.shutdown(); - } - - if (null == builderBasedServer) { - builderBased = CompletableFuture.completedFuture(null); - } else { - builderBased = builderBasedServer.shutdown(); - } - - configBased.toCompletableFuture().join(); - builderBased.toCompletableFuture().join(); - } - - static Stream testDataSource() { - return Stream.of(new TestData("Builder based", builderBasedClient), - new TestData("Config based", configBasedClient)); - } - - @ParameterizedTest - @MethodSource("testDataSource") - void testSsl(TestData testData) { - String response = testData.client - .get() - .request(String.class) - .await(); - - assertThat(testData.type + " SSL server response.", response, is("Hello!")); - } - - private static class TestData { - private final String type; - private final WebClient client; - - private TestData(String type, WebClient client) { - this.type = type; - this.client = client; - } - } -} diff --git a/examples/webserver/tls/src/test/resources/test-application.yaml b/examples/webserver/tls/src/test/resources/test-application.yaml deleted file mode 100644 index 316423f1fb3..00000000000 --- a/examples/webserver/tls/src/test/resources/test-application.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2020 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -config-based: - # switch to available ephemeral port for tests - port: 0 - -builder-based: - port: 0 \ No newline at end of file diff --git a/examples/webserver/tutorial/README.md b/examples/webserver/tutorial/README.md deleted file mode 100644 index fcf0820db0a..00000000000 --- a/examples/webserver/tutorial/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Tutorial Server - -This application demonstrates various WebServer use cases together and in its complexity. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-webserver-tutorial.jar -``` diff --git a/examples/webserver/tutorial/pom.xml b/examples/webserver/tutorial/pom.xml deleted file mode 100644 index 35d06c462f0..00000000000 --- a/examples/webserver/tutorial/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-tutorial - Helidon WebServer Examples Tutorial - - - A tutorial documentation server. - It serves various tutorial articles designed based on project examples. - It is also a complex example demonstrating various web server features. - - - - io.helidon.webserver.examples.tutorial.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.common - helidon-common-reactive - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/CommentService.java b/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/CommentService.java deleted file mode 100644 index c72dd7664af..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/CommentService.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.tutorial; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Flow; -import java.util.stream.Collectors; - -import io.helidon.common.http.DataChunk; -import io.helidon.common.http.MediaType; -import io.helidon.media.common.ContentWriters; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; -import io.helidon.webserver.examples.tutorial.user.User; - - -/** - * Basic service for comments. - */ -public class CommentService implements Service { - - private static final String ROOM_PATH_ID = "room-id"; - - private final ConcurrentHashMap> data = new ConcurrentHashMap<>(); - - @Override - public void update(Routing.Rules routingRules) { - routingRules.get((req, res) -> { - // Register a publisher for comment - res.registerWriter(List.class, MediaType.TEXT_PLAIN.withCharset("UTF-8"), this::publish); - req.next(); - }) - .get("/{" + ROOM_PATH_ID + "}", this::getComments) - .post("/{" + ROOM_PATH_ID + "}", this::addComment); - } - - Flow.Publisher publish(List comments) { - String str = comments.stream() - .map(Comment::toString) - .collect(Collectors.joining("\n")); - return ContentWriters.charSequenceWriter(StandardCharsets.UTF_8) - .apply(str + "\n"); - } - - private void getComments(ServerRequest req, ServerResponse resp) { - String roomId = req.path().param(ROOM_PATH_ID); - //resp.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - List comments = getComments(roomId); - resp.send(comments); - } - - /** - * Returns all comments for the room or an empty list if room doesn't exist. - * - * @param roomId a room ID - * @return a list of comments - */ - public List getComments(String roomId) { - if (roomId == null || roomId.isEmpty()) { - return Collections.emptyList(); - } - - List result = data.get(roomId); - return result == null ? Collections.emptyList() : result; - } - - private void addComment(ServerRequest req, ServerResponse resp) { - String roomId = req.path().param(ROOM_PATH_ID); - User user = req.context() - .get(User.class) - .orElse(User.ANONYMOUS); - req.content() - .as(String.class) - .thenAccept(msg -> addComment(roomId, user, msg)) - .thenRun(resp::send) - .exceptionally(t -> { - req.next(t); - return null; - }); - } - - /** - * Adds new comment into the comment-room. - * - * @param roomName a name of the comment-room - * @param user a user who provides the comment - * @param message a comment message - */ - public void addComment(String roomName, User user, String message) { - if (user == null) { - user = User.ANONYMOUS; - } - List comments = data.computeIfAbsent(roomName, k -> Collections.synchronizedList(new ArrayList<>())); - comments.add(new Comment(user, message)); - } - - /** - * Represents a single comment. - */ - public static class Comment { - private final User user; - private final String message; - - Comment(User user, String message) { - this.user = user; - this.message = message; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (user != null) { - result.append(user.getAlias()); - } - result.append(": "); - result.append(message); - return result.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Comment)) { - return false; - } - - Comment comment = (Comment) o; - - if (user != null ? !user.equals(comment.user) : comment.user != null) { - return false; - } - return message != null ? message.equals(comment.message) : comment.message == null; - } - - @Override - public int hashCode() { - int result = user != null ? user.hashCode() : 0; - result = 31 * result + (message != null ? message.hashCode() : 0); - return result; - } - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/Main.java b/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/Main.java deleted file mode 100644 index 66c92affb14..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/Main.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2017, 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.webserver.examples.tutorial; - -import io.helidon.common.http.MediaType; -import io.helidon.webserver.Routing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.examples.tutorial.user.UserFilter; - -/** - * Application java main class. - * - *

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

    It also serves web server tutorial articles composed from life examples. - */ -public final class Main { - - private Main() { - } - - static Routing createRouting() { - UpperXFilter upperXFilter = new UpperXFilter(); - return Routing.builder() - .any(new UserFilter()) - .any((req, res) -> { - res.registerFilter(upperXFilter); - req.next(); - }) - .register("/article", new CommentService()) - .post("/mgmt/shutdown", (req, res) -> { - res.headers().contentType(MediaType.TEXT_PLAIN.withCharset("UTF-8")); - res.send("Shutting down TUTORIAL server. Good bye!\n"); - // Use reactive API nature to stop the server AFTER the response was sent. - res.whenSent().thenRun(() -> req.webServer().shutdown()); - }) - .build(); - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - // Create a web server instance - int port = 8080; - if (args.length > 0) { - try { - port = Integer.parseInt(args[0]); - } catch (NumberFormatException nfe) { - port = 0; - } - } - - WebServer server = WebServer.builder(createRouting()) - .port(port) - .build(); - - // Start the server and print some info. - server.start().thenAccept(ws -> { - System.out.println("TUTORIAL server is up! http://localhost:" + ws.port()); - System.out.println("Call POST on 'http://localhost:" + ws.port() + "/mgmt/shutdown' to STOP the server!"); - }); - - // Server threads are not demon. NO need to block. Just react. - server.whenShutdown() - .thenRun(() -> System.out.println("TUTORIAL server is DOWN. Good bye!")); - - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/UpperXFilter.java b/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/UpperXFilter.java deleted file mode 100644 index 73b332ddef9..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/UpperXFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.tutorial; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.Flow.Publisher; -import java.util.function.Function; - -import io.helidon.common.http.DataChunk; -import io.helidon.common.reactive.Multi; - - -/** - * All 'x' must be upper case. - *

    - * This is a naive implementation. - */ -public final class UpperXFilter implements Function, Publisher> { - - private static final Charset CHARSET = StandardCharsets.US_ASCII; - private static final byte LOWER_X = "x".getBytes(CHARSET)[0]; - private static final byte UPPER_X = "X".getBytes(CHARSET)[0]; - - @Override - public Publisher apply(Publisher publisher) { - return Multi.create(publisher).map(responseChunk -> { - if (responseChunk == null) { - return null; - } - try { - ByteBuffer[] originalData = responseChunk.data(); - ByteBuffer[] processedData = new ByteBuffer[originalData.length]; - for (int i = 0; i < originalData.length; i++) { - // Naive but works for demo - byte[] buff = new byte[originalData[i].remaining()]; - originalData[i].get(buff); - for (int j = 0; j < buff.length; j++) { - if (buff[j] == LOWER_X) { - buff[j] = UPPER_X; - } - } - processedData[i] = ByteBuffer.wrap(buff); - } - return DataChunk.create(responseChunk.flush(), processedData); - } finally { - responseChunk.release(); - } - }); - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/package-info.java b/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/package-info.java deleted file mode 100644 index 0747e033da1..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A tutorial documentation server. It serves various tutorial articles designed based on project examples. - * - *

    It is also a complex example demonstrating various web server features. - */ -package io.helidon.webserver.examples.tutorial; diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/User.java b/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/User.java deleted file mode 100644 index 9dbc2b595bb..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/User.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.tutorial.user; - -import io.helidon.webserver.Routing; - -/** - * Represents an immutable user. - * - *

    {@link UserFilter} can be registered on Web Server {@link Routing Routing} to provide valid {@link User} - * instance on the request context. - */ -public final class User { - - /** - * Represents an anonymous user. - */ - public static final User ANONYMOUS = new User(); - - private final boolean authenticated; - private final String alias; - private final boolean anonymous; - - /** - * Creates new instance non-anonymous user. - * - * @param authenticated an authenticated is {@code true} if this user identity was validated - * @param alias an alias represents the name of the user which is visible for others - */ - User(boolean authenticated, String alias) { - this.authenticated = authenticated; - this.alias = alias; - this.anonymous = false; - } - - /** - * Creates an unauthenticated user. - * - * @param alias an alias represents the name of the user which is visible for others - */ - User(String alias) { - this(false, alias); - } - - /** - * Creates an anonymous user instance. - */ - private User() { - this.anonymous = true; - this.authenticated = false; - this.alias = "anonymous"; - } - - public boolean isAuthenticated() { - return authenticated; - } - - public String getAlias() { - return alias; - } - - public boolean isAnonymous() { - return anonymous; - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/UserFilter.java b/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/UserFilter.java deleted file mode 100644 index 887c2368830..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/UserFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017, 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.webserver.examples.tutorial.user; - -import io.helidon.webserver.Handler; -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; - -/** - * If used as a {@link Routing Routing} {@link Handler} then assign valid {@link User} instance on the request - * {@link io.helidon.common.context.Context context}. - */ -public class UserFilter implements Handler { - - @Override - public void accept(ServerRequest req, ServerResponse res) { - // Register as a supplier. Thanks to it, user instance is resolved ONLY if it is requested in downstream handlers. - req.context().supply(User.class, - () -> req.headers() - .cookies() - .first("Unauthenticated-User-Alias") - .map(User::new) - .orElse(User.ANONYMOUS)); - req.next(); - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/package-info.java b/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/package-info.java deleted file mode 100644 index d63a5c094c7..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/webserver/examples/tutorial/user/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The server supports authenticated, unauthenticated and anonymous users. Each request is created in the context - * of some user. - * - *

    {@link io.helidon.webserver.examples.tutorial.user.UserFilter UserFilter} is responsible for registration of valid - * {@link io.helidon.webserver.examples.tutorial.user.User User} instance on the context of each request. - */ -package io.helidon.webserver.examples.tutorial.user; diff --git a/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/CommentServiceTest.java b/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/CommentServiceTest.java deleted file mode 100644 index 344e5d217b4..00000000000 --- a/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/CommentServiceTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.tutorial; - -import java.nio.charset.StandardCharsets; - -import io.helidon.common.http.Http; -import io.helidon.common.http.MediaType; -import io.helidon.webserver.Routing; -import io.helidon.webserver.testsupport.MediaPublisher; -import io.helidon.webserver.testsupport.TestClient; -import io.helidon.webserver.testsupport.TestResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsCollectionWithSize.hasSize; -import static org.hamcrest.collection.IsEmptyCollection.empty; - - -/** - * Tests {@link CommentService}. - */ -public class CommentServiceTest { - - @Test - public void addAndGetComments() throws Exception { - CommentService service = new CommentService(); - assertThat(service.getComments("one"), empty()); - assertThat(service.getComments("two"), empty()); - service.addComment("one", null, "aaa"); - assertThat(service.getComments("one"), hasSize(1)); - assertThat(service.getComments("two"), empty()); - service.addComment("one", null, "bbb"); - assertThat(service.getComments("one"), hasSize(2)); - assertThat(service.getComments("two"), empty()); - service.addComment("two", null, "bbb"); - assertThat(service.getComments("one"), hasSize(2)); - assertThat(service.getComments("two"), hasSize(1)); - } - - @Test - public void testRouting() throws Exception { - Routing routing = Routing.builder() - .register(new CommentService()) - .build(); - TestResponse response = TestClient.create(routing) - .path("one") - .get(); - assertThat(response.status(), is(Http.Status.OK_200)); - - // Add first comment - response = TestClient.create(routing) - .path("one") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "aaa")); - assertThat(response.status(), is(Http.Status.OK_200)); - response = TestClient.create(routing) - .path("one") - .get(); - assertThat(response.status(), is(Http.Status.OK_200)); - byte[] data = response.asBytes().toCompletableFuture().get(); - assertThat(new String(data, StandardCharsets.UTF_8), is("anonymous: aaa\n")); - - // Add second comment - response = TestClient.create(routing) - .path("one") - .post(MediaPublisher.create(MediaType.TEXT_PLAIN, "bbb")); - assertThat(response.status(), is(Http.Status.OK_200)); - response = TestClient.create(routing) - .path("one") - .get(); - assertThat(response.status(), is(Http.Status.OK_200)); - data = response.asBytes().toCompletableFuture().get(); - assertThat(new String(data, StandardCharsets.UTF_8), is("anonymous: aaa\nanonymous: bbb\n")); - } -} diff --git a/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/MainTest.java b/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/MainTest.java deleted file mode 100644 index b903d093eda..00000000000 --- a/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/MainTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.tutorial; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.http.Http; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.testsupport.TestClient; -import io.helidon.webserver.testsupport.TestResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Tests {@link Main}. - */ -public class MainTest { - - @Test - public void testShutDown() throws Exception { - TestResponse response = TestClient.create(Main.createRouting()) - .path("/mgmt/shutdown") - .post(); - assertThat(response.status(), is(Http.Status.OK_200)); - CountDownLatch latch = new CountDownLatch(1); - WebServer webServer = response.webServer(); - webServer - .whenShutdown() - .thenRun(latch::countDown); - assertThat(latch.await(10, TimeUnit.SECONDS), is(true)); - } -} diff --git a/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/user/UserFilterTest.java b/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/user/UserFilterTest.java deleted file mode 100644 index cc32418cfca..00000000000 --- a/examples/webserver/tutorial/src/test/java/io/helidon/webserver/examples/tutorial/user/UserFilterTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.tutorial.user; - -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.testsupport.TestClient; -import io.helidon.webserver.testsupport.TestResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Tests {@link UserFilter}. - */ -public class UserFilterTest { - - @Test - public void filter() throws Exception { - AtomicReference userReference = new AtomicReference<>(); - Routing routing = Routing.builder() - .any(new UserFilter()) - .any((req, res) -> { - userReference.set(req.context() - .get(User.class) - .orElse(null)); - res.send(); - }) - .build(); - TestResponse response = TestClient.create(routing) - .path("/") - .get(); - assertThat(userReference.get(), is(User.ANONYMOUS)); - response = TestClient.create(routing) - .path("/") - .header("Cookie", "Unauthenticated-User-Alias=Foo") - .get(); - assertThat(userReference.get().getAlias(), is("Foo")); - } -} diff --git a/examples/webserver/websocket/README.md b/examples/webserver/websocket/README.md deleted file mode 100644 index bbf5c852767..00000000000 --- a/examples/webserver/websocket/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# WebSocket Example - -This application demonstrates use of websockets and REST. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-webserver-websocket.jar -``` - -Open http://localhost:8080/web/index.html in your browser. -`` diff --git a/examples/webserver/websocket/pom.xml b/examples/webserver/websocket/pom.xml deleted file mode 100644 index ed349529c7b..00000000000 --- a/examples/webserver/websocket/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 3.2.7-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-websocket - Helidon WebServer Examples WebSocket - - - Application demonstrates the use of websockets and REST. - - - - io.helidon.webserver.examples.websocket.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver - helidon-webserver-websocket - - - jakarta.inject - jakarta.inject-api - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver - helidon-webserver-test-support - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/Main.java b/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/Main.java deleted file mode 100644 index 5e7f11c3747..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/Main.java +++ /dev/null @@ -1,79 +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. - */ - -package io.helidon.webserver.examples.websocket; - -import java.util.Collections; -import java.util.List; - -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentSupport; -import io.helidon.webserver.websocket.WebSocketRouting; - -import jakarta.websocket.Encoder; -import jakarta.websocket.server.ServerEndpointConfig; - -import static io.helidon.webserver.examples.websocket.MessageBoardEndpoint.UppercaseEncoder; - -/** - * Application demonstrates combination of websocket and REST. - */ -public class Main { - - private Main() { - } - - static WebServer startWebServer() { - List> encoders = Collections.singletonList(UppercaseEncoder.class); - - // Wait for webserver to start before returning - WebServer server = WebServer.builder() - .port(8080) - .routing(r -> r - .register("/web", StaticContentSupport.builder("/WEB") - .welcomeFileName("index.html") - .build()) - .register("/rest", new MessageQueueService()) - ) - .addRouting(WebSocketRouting.builder() - .endpoint("/websocket", ServerEndpointConfig.Builder.create(MessageBoardEndpoint.class, "/board") - .encoders(encoders) - .build()) - .build() - ) - .build() - .start() - .await(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/web"); - - return server; - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - WebServer server = startWebServer(); - - // Server threads are not demon. NO need to block. Just react. - server.whenShutdown() - .thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); - - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageBoardEndpoint.java b/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageBoardEndpoint.java deleted file mode 100644 index b5601ae1253..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageBoardEndpoint.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.websocket; - -import java.util.logging.Logger; - -import jakarta.websocket.CloseReason; -import jakarta.websocket.Encoder; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.MessageHandler; -import jakarta.websocket.Session; - -/** - * Class MessageBoardEndpoint. - */ -public class MessageBoardEndpoint extends Endpoint { - private static final Logger LOGGER = Logger.getLogger(MessageBoardEndpoint.class.getName()); - - private final MessageQueue messageQueue = MessageQueue.instance(); - - @Override - public void onOpen(Session session, EndpointConfig endpointConfig) { - session.addMessageHandler(new MessageHandler.Whole() { - @Override - public void onMessage(String message) { - try { - // Send all messages in the queue - if (message.equals("SEND")) { - while (!messageQueue.isEmpty()) { - session.getBasicRemote().sendObject(messageQueue.pop()); - } - } - } catch (Exception e) { - LOGGER.info(e.getMessage()); - } - } - }); - } - - @Override - public void onClose(Session session, CloseReason closeReason) { - super.onClose(session, closeReason); - } - - @Override - public void onError(Session session, Throwable thr) { - super.onError(session, thr); - } - - /** - * Uppercase encoder. - */ - public static class UppercaseEncoder implements Encoder.Text { - - @Override - public String encode(String s) { - LOGGER.info("UppercaseEncoder encode called"); - return s.toUpperCase(); - } - - @Override - public void init(EndpointConfig config) { - } - - @Override - public void destroy() { - } - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueue.java b/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueue.java deleted file mode 100644 index c127aa4d838..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueue.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.websocket; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * Class MessageQueue. - */ -public class MessageQueue { - - private static final MessageQueue INSTANCE = new MessageQueue(); - - private Queue queue = new ConcurrentLinkedQueue<>(); - - /** - * Return singleton instance of this class. - * - * @return Singleton. - */ - public static MessageQueue instance() { - return INSTANCE; - } - - private MessageQueue() { - } - - /** - * Push string on stack. - * - * @param s String to push. - */ - public void push(String s) { - queue.add(s); - } - - /** - * Pop string from stack. - * - * @return The string or {@code null}. - */ - public String pop() { - return queue.poll(); - } - - /** - * Check if stack is empty. - * - * @return Outcome of test. - */ - public boolean isEmpty() { - return queue.isEmpty(); - } - - /** - * Peek at stack without changing it. - * - * @return String peeked or {@code null}. - */ - public String peek() { - return queue.peek(); - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueueService.java b/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueueService.java deleted file mode 100644 index 8c479a63bf5..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/MessageQueueService.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.webserver.examples.websocket; - -import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerRequest; -import io.helidon.webserver.ServerResponse; -import io.helidon.webserver.Service; - -/** - * Class MessageQueueResource. - */ -public class MessageQueueService implements Service { - - private final MessageQueue messageQueue = MessageQueue.instance(); - - @Override - public void update(Routing.Rules routingRules) { - routingRules.post("/board", this::handlePost); - } - - private void handlePost(ServerRequest request, ServerResponse response) { - request.content() - .as(String.class) - .thenAccept(it -> { - messageQueue.push(it); - response.status(204).send(); - }); - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/package-info.java b/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/package-info.java deleted file mode 100644 index fac35c6fc58..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/webserver/examples/websocket/package-info.java +++ /dev/null @@ -1,25 +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. - */ - -/** - * Application demonstrates combination of the websocket and REST. - * - *

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

    -
    -

    -

    - -

    -

    - -

    -

    -

    History

    -
    -
    - - diff --git a/examples/webserver/websocket/src/main/resources/logging.properties b/examples/webserver/websocket/src/main/resources/logging.properties deleted file mode 100644 index 24de00b0293..00000000000 --- a/examples/webserver/websocket/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -handlers=io.helidon.common.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.server.level=INFO diff --git a/examples/webserver/websocket/src/test/java/io/helidon/webserver/examples/websocket/MessageBoardTest.java b/examples/webserver/websocket/src/test/java/io/helidon/webserver/examples/websocket/MessageBoardTest.java deleted file mode 100644 index 57dca56106a..00000000000 --- a/examples/webserver/websocket/src/test/java/io/helidon/webserver/examples/websocket/MessageBoardTest.java +++ /dev/null @@ -1,131 +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. - */ - -package io.helidon.webserver.examples.websocket; - -import java.io.IOException; -import java.net.URI; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import io.helidon.common.http.Http; -import io.helidon.webclient.WebClient; -import io.helidon.webserver.WebServer; - -import jakarta.websocket.ClientEndpointConfig; -import jakarta.websocket.CloseReason; -import jakarta.websocket.DeploymentException; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.MessageHandler; -import jakarta.websocket.Session; -import org.glassfish.tyrus.client.ClientManager; -import org.glassfish.tyrus.container.jdk.client.JdkClientContainer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.webserver.examples.websocket.Main.startWebServer; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Class MessageBoardTest. - */ -public class MessageBoardTest { - private static final Logger LOGGER = Logger.getLogger(MessageBoardTest.class.getName()); - - private static WebClient restClient = WebClient.create(); - private static ClientManager websocketClient = ClientManager.createClient(JdkClientContainer.class.getName()); - private static WebServer server; - - private String[] messages = { "Whisky", "Tango", "Foxtrot" }; - - @BeforeAll - static void initClass() { - server = startWebServer(); - } - - @AfterAll - static void destroyClass() { - server.shutdown(); - } - - @Test - public void testBoard() throws IOException, DeploymentException, InterruptedException, ExecutionException { - // Post messages using REST resource - URI restUri = URI.create("http://localhost:" + server.port() + "/rest/board"); - for (String message : messages) { - restClient.post() - .uri(restUri) - .submit(message) - .thenAccept(it -> assertThat(it.status(), is(Http.Status.NO_CONTENT_204))) - .toCompletableFuture() - .get(); - LOGGER.info("Posting message '" + message + "'"); - } - - // Now connect to message board using WS and them back - URI websocketUri = URI.create("ws://localhost:" + server.port() + "/websocket/board"); - CountDownLatch messageLatch = new CountDownLatch(messages.length); - ClientEndpointConfig config = ClientEndpointConfig.Builder.create().build(); - - websocketClient.connectToServer(new Endpoint() { - @Override - public void onOpen(Session session, EndpointConfig EndpointConfig) { - try { - // Set message handler to receive messages - session.addMessageHandler(new MessageHandler.Whole() { - @Override - public void onMessage(String message) { - LOGGER.info("Client OnMessage called '" + message + "'"); - messageLatch.countDown(); - if (messageLatch.getCount() == 0) { - try { - session.close(); - } catch (IOException e) { - fail("Unexpected exception " + e); - } - } - } - }); - - // Send an initial message to start receiving - session.getBasicRemote().sendText("SEND"); - } catch (IOException e) { - fail("Unexpected exception " + e); - } - } - - @Override - public void onClose(Session session, CloseReason closeReason) { - LOGGER.info("Client OnClose called '" + closeReason + "'"); - } - - @Override - public void onError(Session session, Throwable thr) { - LOGGER.info("Client OnError called '" + thr + "'"); - - } - }, config, websocketUri); - - // Wait until all messages are received - messageLatch.await(1000000, TimeUnit.SECONDS); - } -} diff --git a/pom.xml b/pom.xml index 8cab3b8a70a..45310bbb484 100644 --- a/pom.xml +++ b/pom.xml @@ -1262,7 +1262,7 @@ helidon-parent,helidon-dependencies,helidon-bom,helidon-se,helidon-mp,io.grpc,he examples - examples + helidon-examples From b97e0996a42c49c45e35b6077a1027a86c0e0a64 Mon Sep 17 00:00:00 2001 From: Maxim Nesen Date: Fri, 1 Mar 2024 23:03:07 +0100 Subject: [PATCH 4/8] 3.x Examples validation flow for external examples repo (#7889) * Examples validation flow for external examples repo Signed-off-by: Maxim Nesen * inline values instead of using variables --------- Signed-off-by: Maxim Nesen Co-authored-by: Romain Grecourt --- .github/workflows/validate.yaml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 25a93894ca0..029036c5b9c 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -121,12 +121,13 @@ jobs: run: etc/scripts/github-tck.sh examples: timeout-minutes: 30 + continue-on-error: true strategy: matrix: os: [ ubuntu-20.04, macos-latest ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} uses: actions/setup-java@v3.11.0 with: @@ -135,8 +136,16 @@ jobs: cache: maven - name: Maven build run: | - mvn -B -e "-Dmaven.test.skip=true" $MAVEN_HTTP_ARGS -DskipTests -Ppipeline install - echo "TBD: validate examples from external repository" + mvn -B -e "-Dmaven.test.skip=true" $MAVEN_HTTP_ARGS -DskipTests -Ppipeline install + - name: Examples checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + repository: helidon-io/helidon-examples.git + ref: dev-3.x + path: helidon-examples + - name: Examples build + run: etc/scripts/build-examples.sh archetypes: timeout-minutes: 30 strategy: From b05a6d2fcd6398aa112360b9a9a657591037322d Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Fri, 1 Mar 2024 16:08:42 -0800 Subject: [PATCH 5/8] Upgrade actions checkout to v4, setup-java to v4.1.0 (#8446) --- .github/workflows/release.yaml | 8 +++---- .github/workflows/snapshotrelease.yaml | 4 ++-- .github/workflows/validate.yaml | 30 +++++++++++++------------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 229774b6ea5..70173f4121a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -21,11 +21,11 @@ jobs: timeout-minutes: 10 runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -37,12 +37,12 @@ jobs: runs-on: ubuntu-20.04 environment: release steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: token: ${{ secrets.SERVICE_ACCOUNT_TOKEN }} fetch-depth: '0' - name: Set up JDK 17 - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/snapshotrelease.yaml b/.github/workflows/snapshotrelease.yaml index 46f0349106a..9c418c2ead5 100644 --- a/.github/workflows/snapshotrelease.yaml +++ b/.github/workflows/snapshotrelease.yaml @@ -22,11 +22,11 @@ jobs: runs-on: ubuntu-20.04 environment: release steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: '0' - name: Set up JDK 17 - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 029036c5b9c..542e71aeb0a 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -29,11 +29,11 @@ jobs: timeout-minutes: 10 runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -44,9 +44,9 @@ jobs: timeout-minutes: 10 runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -57,9 +57,9 @@ jobs: timeout-minutes: 45 runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -73,9 +73,9 @@ jobs: os: [ ubuntu-20.04 ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -94,9 +94,9 @@ jobs: timeout-minutes: 10 runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -110,9 +110,9 @@ jobs: os: [ ubuntu-20.04 ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -129,7 +129,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -155,7 +155,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} @@ -180,7 +180,7 @@ jobs: set-java-home: false cache: maven - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4.1.0 with: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} From a60ff40e219295be5243a855370c3820c132a1ed Mon Sep 17 00:00:00 2001 From: Maxim Nesen Date: Tue, 5 Mar 2024 19:41:37 +0100 Subject: [PATCH 6/8] security review for archetypes (#8454) Signed-off-by: Maxim Nesen --- .../files/application.http-signature.yaml | 4 ++-- .../files/src/main/resources/keystore.p12 | Bin 2700 -> 2693 bytes .../src/main/archetype/mp/custom/database.xml | 8 ++++---- .../src/main/archetype/se/custom/database.xml | 6 +++--- .../se/custom/files/application.mysql.yaml | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/archetypes/helidon/src/main/archetype/common/files/application.http-signature.yaml b/archetypes/helidon/src/main/archetype/common/files/application.http-signature.yaml index 2f86e37e46e..d4fb707494d 100644 --- a/archetypes/helidon/src/main/archetype/common/files/application.http-signature.yaml +++ b/archetypes/helidon/src/main/archetype/common/files/application.http-signature.yaml @@ -5,7 +5,7 @@ - key-id: "service1-hmac" principal-name: "Service1 - HMAC signature" # See [EncryptionFilter](https://helidon.io/docs/latest/apidocs/io.helidon.config.encryption/io/helidon/config/encryption/EncryptionFilter.html) for details about encrypting passwords in configuration files. - hmac.secret: "somePasswordForHmacShouldBeEncrypted" + hmac.secret: "changeit" - key-id: "service1-rsa" principal-name: "Service1 - RSA signature" public-key: @@ -17,6 +17,6 @@ # defaults to jdk default # keystore-type: "PKCS12" # password of the keystore - passphrase: "password" + passphrase: "changeit" # alias of the certificate to get public key from cert.alias: "service_cert" diff --git a/archetypes/helidon/src/main/archetype/common/files/src/main/resources/keystore.p12 b/archetypes/helidon/src/main/archetype/common/files/src/main/resources/keystore.p12 index ff2c52d6694ae5c23a1b15d971935a9fa33ba1d4..96df596265a4799186924602afa1d101e5e80baa 100644 GIT binary patch literal 2693 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 delta 2665 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 + + + io.helidon.tests.integration + helidon-tests-integration + 3.2.7-SNAPSHOT + + 4.0.0 + + helidon-tests-integration-mp-gh-8478 + Helidon Tests Integration MP GH 8478 + Reproducer for Github issue #8478 - Fault tolerance config fails in HelidonTest + + + + io.helidon.microprofile.server + helidon-microprofile-server + + + io.helidon.microprofile + helidon-microprofile-fault-tolerance + + + io.helidon.microprofile.metrics + helidon-microprofile-metrics + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + io.helidon.microprofile.tests + helidon-microprofile-tests-junit5 + test + + + \ No newline at end of file diff --git a/tests/integration/mp-gh-8478/src/main/java/io/helidon/tests/integration/gh8478/Gh8478Resource.java b/tests/integration/mp-gh-8478/src/main/java/io/helidon/tests/integration/gh8478/Gh8478Resource.java new file mode 100644 index 00000000000..9605e0c8bb5 --- /dev/null +++ b/tests/integration/mp-gh-8478/src/main/java/io/helidon/tests/integration/gh8478/Gh8478Resource.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.tests.integration.gh8478; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; + +import jakarta.ws.rs.ForbiddenException; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.faulttolerance.Retry; +import org.eclipse.microprofile.faulttolerance.Timeout; + +@Path("/greet") +@Retry +@Timeout +public class Gh8478Resource { + private static final Logger LOGGER = Logger.getLogger(Gh8478Resource.class.getName()); + + static final AtomicInteger COUNTER = new AtomicInteger(); + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getDefaultMessage() throws InterruptedException { + COUNTER.incrementAndGet(); + + LOGGER.info("Attempt #" + COUNTER.get() + " before sleep."); + Thread.sleep(100); + if (COUNTER.get() == 3) { + LOGGER.info("Attempt #" + COUNTER.get() + " returning response."); + return "Hello World!"; + } + + LOGGER.info("Attempt #" + COUNTER.get() + " throwing exception."); + throw new ForbiddenException("Intentional exception"); + } +} diff --git a/tests/integration/mp-gh-8478/src/main/resources/META-INF/beans.xml b/tests/integration/mp-gh-8478/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000000..69f490f1afc --- /dev/null +++ b/tests/integration/mp-gh-8478/src/main/resources/META-INF/beans.xml @@ -0,0 +1,25 @@ + + + + diff --git a/tests/integration/mp-gh-8478/src/main/resources/application.yaml b/tests/integration/mp-gh-8478/src/main/resources/application.yaml new file mode 100644 index 00000000000..eb57790080c --- /dev/null +++ b/tests/integration/mp-gh-8478/src/main/resources/application.yaml @@ -0,0 +1,24 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +server: + port: 8080 + host: 0.0.0.0 + +io.helidon.tests.integration.gh8478.Gh8478Resource/Retry/enabled: true +io.helidon.tests.integration.gh8478.Gh8478Resource/Timeout/enabled: true +io.helidon.tests.integration.gh8478.Gh8478Resource/Retry/maxRetries: 3 +io.helidon.tests.integration.gh8478.Gh8478Resource/Timeout/value: 5000 diff --git a/tests/integration/mp-gh-8478/src/main/resources/logging.properties b/tests/integration/mp-gh-8478/src/main/resources/logging.properties new file mode 100644 index 00000000000..cb327be85a2 --- /dev/null +++ b/tests/integration/mp-gh-8478/src/main/resources/logging.properties @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +handlers=io.helidon.common.HelidonConsoleHandler +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n + +.level=WARNING + +io.helidon.level=INFO diff --git a/tests/integration/mp-gh-8478/src/test/java/io/helidon/tests/integration/gh8478/Gh8478Test.java b/tests/integration/mp-gh-8478/src/test/java/io/helidon/tests/integration/gh8478/Gh8478Test.java new file mode 100644 index 00000000000..74664ecd1ba --- /dev/null +++ b/tests/integration/mp-gh-8478/src/test/java/io/helidon/tests/integration/gh8478/Gh8478Test.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.tests.integration.gh8478; + +import io.helidon.microprofile.tests.junit5.AddConfig; +import io.helidon.microprofile.tests.junit5.HelidonTest; + +import jakarta.inject.Inject; +import jakarta.ws.rs.ForbiddenException; +import jakarta.ws.rs.client.WebTarget; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +@HelidonTest +@AddConfig(key ="io.helidon.tests.integration.gh8478.Gh8478Resource/Retry/enabled", value = "true") +@AddConfig(key ="io.helidon.tests.integration.gh8478.Gh8478Resource/Retry/maxRetries", value = "1") +@AddConfig(key ="io.helidon.tests.integration.gh8478.Gh8478Resource/Timeout/enabled", value = "true") +@AddConfig(key ="io.helidon.tests.integration.gh8478.Gh8478Resource/Timeout/value", value = "10000") +class Gh8478Test { + @Inject + private WebTarget target; + + @BeforeEach + void setUp() { + Gh8478Resource.COUNTER.set(0); + } + + @Test + void test() { + assertThrows(ForbiddenException.class, () -> target + .path("/greet") + .request() + .get(String.class)); + } +} diff --git a/tests/integration/mp-gh-8478/src/test/java/io/helidon/tests/integration/gh8478/Gh8478YamlTest.java b/tests/integration/mp-gh-8478/src/test/java/io/helidon/tests/integration/gh8478/Gh8478YamlTest.java new file mode 100644 index 00000000000..9e89cb4009a --- /dev/null +++ b/tests/integration/mp-gh-8478/src/test/java/io/helidon/tests/integration/gh8478/Gh8478YamlTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.tests.integration.gh8478; + +import io.helidon.microprofile.tests.junit5.HelidonTest; + +import jakarta.inject.Inject; +import jakarta.ws.rs.client.WebTarget; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@HelidonTest +class Gh8478YamlTest { + @Inject + private WebTarget target; + + @BeforeEach + void setUp() { + Gh8478Resource.COUNTER.set(0); + } + + @Test + void test() { + String response = target + .path("/greet") + .request() + .get(String.class); + + assertThat(response, is("Hello World!")); + } +} diff --git a/tests/integration/mp-gh-8478/src/test/resources/application.yaml b/tests/integration/mp-gh-8478/src/test/resources/application.yaml new file mode 100644 index 00000000000..21177c8fd3e --- /dev/null +++ b/tests/integration/mp-gh-8478/src/test/resources/application.yaml @@ -0,0 +1,20 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +config_ordinal: 500 +io.helidon.tests.integration.gh8478.Gh8478Resource/Retry/enabled: true +io.helidon.tests.integration.gh8478.Gh8478Resource/Timeout/enabled: false +io.helidon.tests.integration.gh8478.Gh8478Resource/Retry/maxRetries: 3 diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml index 202d1c2a661..70db8649218 100644 --- a/tests/integration/pom.xml +++ b/tests/integration/pom.xml @@ -51,6 +51,7 @@ mp-gh-4123 mp-gh-4654 mp-gh-5328 + mp-gh-8478 kafka jpa jms