From 39fc0b2f8a732a98dbab09fb3fad268447024ec3 Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Tue, 4 Jun 2024 12:34:21 +0200 Subject: [PATCH 1/9] updated to latest Helidon version --- .dockerignore | 1 - .github/workflows/maven.yml | 41 +- .gitignore | 139 +--- Dockerfile | 29 - Dockerfile.jlink | 25 - Dockerfile.native | 29 - README.md | 144 +---- docker/server.pem | 60 ++ docker/start_db.sh | 117 ++++ docker/start_db_single.sh | 23 - pom.xml | 67 +- .../com/example/myproject/ArangoConfig.java | 62 ++ .../com/example/myproject/ArangoProvider.java | 36 ++ .../example/myproject/ArangoResource.java} | 17 +- .../example/myproject}/ArangoService.java | 6 +- .../com/example/myproject/package-info.java | 2 + src/main/java/graal/BrotliSubstitutions.java | 20 + .../java/graal/graal/JdkSubstitutions.java | 98 +++ .../java/graal/graal/VertxSubstitutions.java | 197 ++++++ src/main/java/graal/graal/package-info.java | 4 + .../java/graal/netty/EmptyByteBufStub.java | 33 + .../HttpContentCompressorSubstitutions.java | 68 ++ .../graal/netty/graal/NettySubstitutions.java | 606 ++++++++++++++++++ .../graal/netty/graal/ZLibSubstitutions.java | 66 ++ src/main/java/graal/netty/package-info.java | 4 + .../quickstart/mp/ArangoConfiguration.java | 19 - .../quickstart/mp/jsonb/JsonConfig.java | 23 - .../quickstart/mp/jsonb/VersionAdapter.java | 29 - .../examples/quickstart/mp/package-info.java | 2 - src/main/resources/META-INF/beans.xml | 14 +- .../META-INF/microprofile-config.properties | 8 +- .../native-image.properties | 8 + .../reflect-config.json | 6 + .../META-INF/native-image/reflect-config.json | 1 - .../META-INF/resources/adb.truststore | Bin 0 -> 2251 bytes src/main/resources/logging.properties | 7 +- .../java/com/example/myproject/MainTest.java | 43 ++ .../quickstart/mp/MainIntegrationTest.java | 27 - .../examples/quickstart/mp/MainTest.java | 44 -- .../META-INF/microprofile-config.properties | 0 src/test/resources/application-test.yaml | 2 + 41 files changed, 1550 insertions(+), 577 deletions(-) delete mode 100644 .dockerignore delete mode 100644 Dockerfile delete mode 100644 Dockerfile.jlink delete mode 100644 Dockerfile.native create mode 100644 docker/server.pem create mode 100755 docker/start_db.sh delete mode 100755 docker/start_db_single.sh create mode 100644 src/main/java/com/example/myproject/ArangoConfig.java create mode 100644 src/main/java/com/example/myproject/ArangoProvider.java rename src/main/java/{io/helidon/examples/quickstart/mp/GreetingResource.java => com/example/myproject/ArangoResource.java} (53%) rename src/main/java/{io/helidon/examples/quickstart/mp => com/example/myproject}/ArangoService.java (75%) create mode 100644 src/main/java/com/example/myproject/package-info.java create mode 100644 src/main/java/graal/BrotliSubstitutions.java create mode 100644 src/main/java/graal/graal/JdkSubstitutions.java create mode 100644 src/main/java/graal/graal/VertxSubstitutions.java create mode 100644 src/main/java/graal/graal/package-info.java create mode 100644 src/main/java/graal/netty/EmptyByteBufStub.java create mode 100644 src/main/java/graal/netty/graal/HttpContentCompressorSubstitutions.java create mode 100644 src/main/java/graal/netty/graal/NettySubstitutions.java create mode 100644 src/main/java/graal/netty/graal/ZLibSubstitutions.java create mode 100644 src/main/java/graal/netty/package-info.java delete mode 100644 src/main/java/io/helidon/examples/quickstart/mp/ArangoConfiguration.java delete mode 100644 src/main/java/io/helidon/examples/quickstart/mp/jsonb/JsonConfig.java delete mode 100644 src/main/java/io/helidon/examples/quickstart/mp/jsonb/VersionAdapter.java delete mode 100644 src/main/java/io/helidon/examples/quickstart/mp/package-info.java create mode 100644 src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties create mode 100644 src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/reflect-config.json delete mode 100644 src/main/resources/META-INF/native-image/reflect-config.json create mode 100644 src/main/resources/META-INF/resources/adb.truststore create mode 100644 src/test/java/com/example/myproject/MainTest.java delete mode 100644 src/test/java/io/helidon/examples/quickstart/mp/MainIntegrationTest.java delete mode 100644 src/test/java/io/helidon/examples/quickstart/mp/MainTest.java create mode 100644 src/test/resources/META-INF/microprofile-config.properties create mode 100644 src/test/resources/application-test.yaml diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index c8b241f..0000000 --- a/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 30d3674..69bd72b 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -5,34 +5,31 @@ on: push jobs: verify: - + timeout-minutes: 10 runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - java-version: - - java11 - graalvm-version: - - 20.0.0 - steps: - - uses: actions/checkout@v1 - - name: Setup GraalVM CE - uses: rinx/setup-graalvm-ce@v0.0.1 + - uses: actions/checkout@v2 + - uses: graalvm/setup-graalvm@v1 with: - graalvm-version: ${{ matrix.graalvm-version }} - java-version: ${{ matrix.java-version }} - - name: setup-native-image - run: gu install native-image + java-version: '21.0.2' + distribution: 'graalvm-community' + cache: 'maven' + native-image-job-reports: 'true' + github-token: ${{ secrets.GITHUB_TOKEN }} - name: Info run: mvn -version - name: Start Database - run: ./docker/start_db_single.sh docker.io/arangodb/arangodb:3.6.4 - - name: compile native - run: mvn package -Pnative-image -DskipTests - - name: start native server - run: ./target/arango-helidon-native-example -Dserver.port=8081 & + run: ./docker/start_db.sh + env: + SSL: true - name: test run: mvn test - + - name: package-native + run: mvn -Pnative-image package + - name: start-native + run: ./target/arango-helidon-native-example & + - name: wait + run: sleep 1 + - name: test-version + run: curl -v --fail http://localhost:8080/version diff --git a/.gitignore b/.gitignore index 284a495..6f40536 100644 --- a/.gitignore +++ b/.gitignore @@ -1,117 +1,9 @@ -# Created by .ignore support plugin (hsz.mobi) -### Linux template -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Maven template -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -# https://github.com/takari/maven-wrapper#usage-without-binary-jar -.mvn/wrapper/maven-wrapper.jar - -### Java template # Compiled class file *.class -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ +# Maven +target/ +.m2/ # Package Files # *.jar @@ -122,8 +14,25 @@ buildNumber.properties *.tar.gz *.rar -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -.idea - +# IntelliJ Idea +.idea/* +!.idea/runConfigurations +*.iws +*.ipr *.iml +*.releaseBackup +atlassian-ide-plugin.xml + +# Netbeans +nbactions.xml +nb-configuration.xml + +# Eclipse +.settings +.settings/ +.project +.classpath +.factorypath + +/docker/jwtHeader +/docker/jwtSecret diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 35500a1..0000000 --- a/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ - -# 1st stage, build the app -FROM maven:3.6-jdk-11 as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -DskipTests - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:11-jre-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/arango-helidon-native-example.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "arango-helidon-native-example.jar"] - -EXPOSE 8080 diff --git a/Dockerfile.jlink b/Dockerfile.jlink deleted file mode 100644 index 2877a56..0000000 --- a/Dockerfile.jlink +++ /dev/null @@ -1,25 +0,0 @@ - -# 1st stage, build the app -FROM maven:3.6.3-jdk-11-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -DskipTests - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/arango-helidon-native-example ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/Dockerfile.native b/Dockerfile.native deleted file mode 100644 index b54f328..0000000 --- a/Dockerfile.native +++ /dev/null @@ -1,29 +0,0 @@ - -# 1st stage, build the app -FROM helidon/jdk11-graalvm-maven:20.0.0 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 -Pnative-image -Dnative.image.skip -DskipTests - -# 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/harango-helidon-native-example . - -ENTRYPOINT ["./arango-helidon-native-example"] - -EXPOSE 8080 diff --git a/README.md b/README.md index b7ceb55..7bc8cbd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Helidon Quickstart MP +# arango-helidon-native-example Sample Helidon MP project that includes multiple REST operations. @@ -7,12 +7,12 @@ Sample Helidon MP project that includes multiple REST operations. Start a local database: ```shell script -docker run -e ARANGO_ROOT_PASSWORD=test -p 8529:8529 --rm arangodb:3.6 +SSL=true ./docker/start_db.sh ``` ## Build and run -With JDK11+ +With JDK21 ```bash mvn package java -jar target/arango-helidon-native-example.jar @@ -20,148 +20,22 @@ java -jar target/arango-helidon-native-example.jar ## Exercise the application +Basic: ``` curl -X GET http://localhost:8080/version -{"version":"3.6.4","license":"COMMUNITY","server":"arango"} +{"license":"COMMUNITY","server":"arango","version":"3.12.0-2"} ``` -## Try health and metrics +## Building a Native Image -``` -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 arango-helidon-native-example . -``` - -## Start the application with Docker +You can build a native binary using Maven as follows: ``` -docker run --rm -p 8080:8080 arango-helidon-native-example:latest +mvn -Pnative-image package -DskipTests ``` -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 arango-helidon-native-example # 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, the version - currently supported for Helidon is `20.0`. - -``` -# 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: +You can then execute your native executable with: ``` ./target/arango-helidon-native-example ``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -``` -docker build -t arango-helidon-native-example-native -f Dockerfile.native . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 arango-helidon-native-example-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/arango-helidon-native-example/bin/start -``` - -### Multi-stage Docker build - -Build the "jlink" Docker Image - -``` -docker build -t arango-helidon-native-example-jlink -f Dockerfile.jlink . -``` - -Start the application: - -``` -docker run --rm -p 8080:8080 arango-helidon-native-example-jlink:latest -``` - -See the start script help: - -``` -docker run --rm arango-helidon-native-example-jlink:latest --help -``` - diff --git a/docker/server.pem b/docker/server.pem new file mode 100644 index 0000000..c97c302 --- /dev/null +++ b/docker/server.pem @@ -0,0 +1,60 @@ +Bag Attributes + friendlyName: arangotest + localKeyID: 54 69 6D 65 20 31 36 30 34 32 35 36 36 37 39 38 35 34 +Key Attributes: +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1WiDnd4+uCmMG +539ZNZB8NwI0RZF3sUSQGPx3lkqaFTZVEzMZL76HYvdc9Qg7difyKyQ09RLSpMAL +X9euSseD7bZGnfQH52BnKcT09eQ3wh7aVQ5sN2omygdHLC7X9usntxAfv7Nzmvdo +gNXoJQyY/hSZff7RIqWH8NnAUKkjqOe6Bf5LDbxHKESmrFBxOCOnhcpvZWetwpiR +dJVPwUn5P82CAZzfiBfmBZnB7D0l+/6Cv4jMuH26uAIcixnVekBQzl1RgwczuiZf +2MGO64vDMMJJWE9ClZF1uQuQrwXF6qwhuP1Hnkii6wNbTtPWlGSkqeutr004+Hzb +f8KnRY4PAgMBAAECggEAKi1d/bdW2TldMpvgiFTm15zLjHCpllbKBWFqRj3T9+X7 +Duo6Nh9ehopD0YDDe2DNhYr3DsH4sLjUWVDfDpAhutMsU1wlBzmOuC+EuRv/CeDB +4DFr+0sgCwlti+YAtwWcR05SF7A0Ai0GYW2lUipbtbFSBSjCfM08BlPDsPCRhdM8 +DhBn3S45aP7oC8BdhG/etg+DfXW+/nyNwEcMCYG97bzXNjzYpCQjo/bTHdh2UPYM +4WEAqFzZ5jir8LVS3v7GqpqPmk6FnHJOJpfpOSZoPqnfpIw7SVlNsXHvDaHGcgYZ +Xec7rLQlBuv4RZU7OlGJpK2Ng5kvS9q3nfqqn7YIMQKBgQDqSsYnE+k6CnrSpa2W +B9W/+PChITgkA46XBUUjAueJ7yVZQQEOzl0VI6RoVBp3t66eO8uM9omO8/ogHXku +Ei9UUIIfH4BsSP7G5A06UC/FgReDxwBfbRuS+lupnmc348vPDkFlJZ4hDgWflNev +7tpUbljSAqUea1VhdBy146V4qwKBgQDGJ6iL1+A9uUM+1UklOAPpPhTQ8ZQDRCj7 +7IMVcbzWYvCMuVNXzOWuiz+VYr3IGCJZIbxbFDOHxGF4XKJnk0vm1qhQQME0PtAF +i1jIfsxpj8KKJl9Uad+XLQCYRV8mIZlhsd/ErRJuz6FyqevKH3nFIb0ggF3x2d06 +odTHuj4ILQKBgCUsI/BDSne4/e+59aaeK52/w33tJVkhb1gqr+N0LIRH+ycEF0Tg +HQijlQwwe9qOvBfC6PK+kuipcP/zbSyQGg5Ij7ycZOXJVxL7T9X2rv2pE7AGvNpn +Fz7klfJ9fWbyr310h4+ivkoETYQaO3ZgcSeAMntvi/8djHhf0cZSDgjtAoGBAKvQ +TUNcHjJGxfjgRLkB1dpSmwgEv7sJSaQOkiZw5TTauwq50nsJzYlHcg1cfYPW8Ulp +iAFNBdVNwNn1MFgwjpqMO4rCawObBxIXnhbSYvmQzjStSvFNj7JsMdzWIcdVUMI1 +0fmdu6LbY3ihvzIVkqcMNwnMZCjFKB6jnXTElu7NAoGAS0gNPD/bfzWAhZBBYp9/ +SLGOvjHKrSVWGwDiqdAGuh6xg+1C3F+XpiITP6d3Wv3PCJ/Gia5isQPSMaXG+xTt +6huBgFlksHqr0tsQA9dcgGW7BDr5VhRq5/WinaLhGGy1R+i2zbDmQXgHbCO+RH/s +bD9F4LZ3RoXmGHLW0IUggPw= +-----END PRIVATE KEY----- +Bag Attributes + friendlyName: arangotest + localKeyID: 54 69 6D 65 20 31 36 30 34 32 35 36 36 37 39 38 35 34 +subject=C = Unknown, ST = Unknown, L = Unknown, O = Unknown, OU = Unknown, CN = localhost + +issuer=C = Unknown, ST = Unknown, L = Unknown, O = Unknown, OU = Unknown, CN = localhost + +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIEeDCzXzANBgkqhkiG9w0BAQsFADBuMRAwDgYDVQQGEwdV +bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD +VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRIwEAYDVQQDEwlsb2NhbGhv +c3QwHhcNMjAxMTAxMTg1MTE5WhcNMzAxMDMwMTg1MTE5WjBuMRAwDgYDVQQGEwdV +bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD +VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRIwEAYDVQQDEwlsb2NhbGhv +c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1WiDnd4+uCmMG539Z +NZB8NwI0RZF3sUSQGPx3lkqaFTZVEzMZL76HYvdc9Qg7difyKyQ09RLSpMALX9eu +SseD7bZGnfQH52BnKcT09eQ3wh7aVQ5sN2omygdHLC7X9usntxAfv7NzmvdogNXo +JQyY/hSZff7RIqWH8NnAUKkjqOe6Bf5LDbxHKESmrFBxOCOnhcpvZWetwpiRdJVP +wUn5P82CAZzfiBfmBZnB7D0l+/6Cv4jMuH26uAIcixnVekBQzl1RgwczuiZf2MGO +64vDMMJJWE9ClZF1uQuQrwXF6qwhuP1Hnkii6wNbTtPWlGSkqeutr004+Hzbf8Kn +RY4PAgMBAAGjITAfMB0GA1UdDgQWBBTBrv9Awynt3C5IbaCNyOW5v4DNkTANBgkq +hkiG9w0BAQsFAAOCAQEAIm9rPvDkYpmzpSIhR3VXG9Y71gxRDrqkEeLsMoEyqGnw +/zx1bDCNeGg2PncLlW6zTIipEBooixIE9U7KxHgZxBy0Et6EEWvIUmnr6F4F+dbT +D050GHlcZ7eOeqYTPYeQC502G1Fo4tdNi4lDP9L9XZpf7Q1QimRH2qaLS03ZFZa2 +tY7ah/RQqZL8Dkxx8/zc25sgTHVpxoK853glBVBs/ENMiyGJWmAXQayewY3EPt/9 +wGwV4KmU3dPDleQeXSUGPUISeQxFjy+jCw21pYviWVJTNBA9l5ny3GhEmcnOT/gQ +HCvVRLyGLMbaMZ4JrPwb+aAtBgrgeiK4xeSMMvrbhw== +-----END CERTIFICATE----- diff --git a/docker/start_db.sh b/docker/start_db.sh new file mode 100755 index 0000000..619abc8 --- /dev/null +++ b/docker/start_db.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +# Configuration environment variables: +# STARTER_MODE: (single|cluster|activefailover), default single +# DOCKER_IMAGE: ArangoDB docker image, default docker.io/arangodb/arangodb:latest +# SSL: (true|false), default false +# DATABASE_EXTENDED_NAMES: (true|false), default false +# ARANGO_LICENSE_KEY: only required for ArangoDB Enterprise + +# EXAMPLE: +# STARTER_MODE=cluster SSL=true ./start_db.sh + +STARTER_MODE=${STARTER_MODE:=single} +DOCKER_IMAGE=${DOCKER_IMAGE:=docker.io/arangodb/arangodb:latest} +SSL=${SSL:=false} +DATABASE_EXTENDED_NAMES=${DATABASE_EXTENDED_NAMES:=false} + +STARTER_DOCKER_IMAGE=docker.io/arangodb/arangodb-starter:latest +GW=172.28.0.1 +docker network create arangodb --subnet 172.28.0.0/16 + +# exit when any command fails +set -e + +docker pull $STARTER_DOCKER_IMAGE +docker pull $DOCKER_IMAGE + +LOCATION=$(pwd)/$(dirname "$0") + +echo "Averysecretword" > "$LOCATION"/jwtSecret +docker run --rm -v "$LOCATION"/jwtSecret:/jwtSecret "$STARTER_DOCKER_IMAGE" auth header --auth.jwt-secret /jwtSecret > "$LOCATION"/jwtHeader +AUTHORIZATION_HEADER=$(cat "$LOCATION"/jwtHeader) + +STARTER_ARGS= +SCHEME=http +ARANGOSH_SCHEME=http+tcp +COORDINATORS=("$GW:8529" "$GW:8539" "$GW:8549") + +if [ "$STARTER_MODE" == "single" ]; then + COORDINATORS=("$GW:8529") +fi + +if [ "$SSL" == "true" ]; then + STARTER_ARGS="$STARTER_ARGS --ssl.keyfile=server.pem" + SCHEME=https + ARANGOSH_SCHEME=http+ssl +fi + +if [ "$DATABASE_EXTENDED_NAMES" == "true" ]; then + STARTER_ARGS="${STARTER_ARGS} --all.database.extended-names-databases=true" +fi + +if [ "$USE_MOUNTED_DATA" == "true" ]; then + STARTER_ARGS="${STARTER_ARGS} --starter.data-dir=/data" + MOUNT_DATA="-v $LOCATION/data:/data" + echo $MOUNT_DATA +fi + +docker run -d \ + --name=adb \ + -p 8528:8528 \ + -v "$LOCATION"/server.pem:/server.pem \ + -v "$LOCATION"/jwtSecret:/jwtSecret \ + $MOUNT_DATA \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e ARANGO_LICENSE_KEY="$ARANGO_LICENSE_KEY" \ + $STARTER_DOCKER_IMAGE \ + $STARTER_ARGS \ + --docker.net-mode=default \ + --docker.container=adb \ + --auth.jwt-secret=/jwtSecret \ + --starter.address="${GW}" \ + --docker.image="${DOCKER_IMAGE}" \ + --starter.local --starter.mode=${STARTER_MODE} --all.log.level=debug --all.log.output=+ --log.verbose --all.server.descriptors-minimum=1024 + + +wait_server() { + # shellcheck disable=SC2091 + until $(curl --output /dev/null --insecure --fail --silent --head -i -H "$AUTHORIZATION_HEADER" "$SCHEME://$1/_api/version"); do + printf '.' + sleep 1 + done +} + +echo "Waiting..." + +for a in ${COORDINATORS[*]} ; do + wait_server "$a" +done + +set +e +for a in ${COORDINATORS[*]} ; do + echo "" + echo "Setting username and password..." + docker run --rm ${DOCKER_IMAGE} arangosh --server.endpoint="$ARANGOSH_SCHEME://$a" --server.authentication=false --javascript.execute-string='require("org/arangodb/users").update("root", "test")' +done +set -e + +for a in ${COORDINATORS[*]} ; do + echo "" + echo "Requesting endpoint version..." + curl -u root:test --insecure --fail "$SCHEME://$a/_api/version" +done + +echo "" +echo "" +echo "Done, your deployment is reachable at: " +for a in ${COORDINATORS[*]} ; do + echo "$SCHEME://$a" + echo "" +done + +if [ "$STARTER_MODE" == "activefailover" ]; then + LEADER=$("$LOCATION"/find_active_endpoint.sh) + echo "Leader: $SCHEME://$LEADER" + echo "" +fi diff --git a/docker/start_db_single.sh b/docker/start_db_single.sh deleted file mode 100755 index 2759b7c..0000000 --- a/docker/start_db_single.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# USAGE: -# export ARANGO_LICENSE_KEY= -# ./start_db_single.sh - -# EXAMPLE: -# ./start_db_single.sh docker.io/arangodb/arangodb:3.6.2 - -docker pull "$1" - -docker network create arangodb --subnet 172.28.0.0/16 - -docker run -d -p 8529:8529 -e ARANGO_ROOT_PASSWORD=test -e ARANGO_LICENSE_KEY="$ARANGO_LICENSE_KEY" --network arangodb --ip 172.28.3.1 "$1" - -echo "waiting for arangodb ..." - -# shellcheck disable=SC2091 -until $(curl --output /dev/null --silent --head --fail -i -u root:test 'http://localhost:8529/_api/version'); do - printf '.' - sleep 1 -done -echo "READY!" diff --git a/pom.xml b/pom.xml index ca14432..004f80b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,55 +1,51 @@ - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 io.helidon.applications helidon-mp - 2.0.0 + 4.0.8 + - io.helidon.examples + com.arangodb arango-helidon-native-example 1.0-SNAPSHOT - myproject com.arangodb arangodb-java-driver - 6.7.0 + 7.7.0-SNAPSHOT + + + org.graalvm.sdk + graal-sdk + 24.0.1 + provided io.helidon.microprofile.bundles - helidon-microprofile + helidon-microprofile-core - org.jboss - jandex + jakarta.json.bind + jakarta.json.bind-api + + + org.glassfish.jersey.media + jersey-media-json-binding runtime - true - jakarta.activation - jakarta.activation-api + io.helidon.logging + helidon-logging-jul + runtime + + + io.smallrye + jandex runtime @@ -57,6 +53,17 @@ junit-jupiter-api test + + io.helidon.microprofile.testing + helidon-microprofile-testing-junit5 + test + + + org.assertj + assertj-core + 3.25.3 + test + @@ -71,7 +78,7 @@ - org.jboss.jandex + io.smallrye jandex-maven-plugin diff --git a/src/main/java/com/example/myproject/ArangoConfig.java b/src/main/java/com/example/myproject/ArangoConfig.java new file mode 100644 index 0000000..bd8c34e --- /dev/null +++ b/src/main/java/com/example/myproject/ArangoConfig.java @@ -0,0 +1,62 @@ +package com.example.myproject; + + +import com.arangodb.Protocol; +import com.arangodb.config.ArangoConfigProperties; +import com.arangodb.config.HostDescription; +import jakarta.enterprise.context.Dependent; +import org.eclipse.microprofile.config.inject.ConfigProperties; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.util.List; +import java.util.Optional; + +@Dependent +@ConfigProperties(prefix = "adb") +public class ArangoConfig implements ArangoConfigProperties { + private List hosts; + private Optional protocol; + private String password; + private Boolean useSsl; + + @ConfigProperty(name = "ssl.trustStoreFile") + private String trustStoreFile; + + @ConfigProperty(name = "ssl.trustStorePassword") + private String trustStorePassword; + + @ConfigProperty(name = "ssl.trustStoreType") + private String trustStoreType; + + @Override + public Optional> getHosts() { + return Optional.ofNullable(hosts); + } + + @Override + public Optional getProtocol() { + return protocol; + } + + @Override + public Optional getPassword() { + return Optional.ofNullable(password); + } + + @Override + public Optional getUseSsl() { + return Optional.ofNullable(useSsl); + } + + public String getTrustStoreFile() { + return trustStoreFile; + } + + public String getTrustStorePassword() { + return trustStorePassword; + } + + public String getTrustStoreType() { + return trustStoreType; + } +} diff --git a/src/main/java/com/example/myproject/ArangoProvider.java b/src/main/java/com/example/myproject/ArangoProvider.java new file mode 100644 index 0000000..8217247 --- /dev/null +++ b/src/main/java/com/example/myproject/ArangoProvider.java @@ -0,0 +1,36 @@ +package com.example.myproject; + +import com.arangodb.ArangoDB; +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Produces; +import org.eclipse.microprofile.config.inject.ConfigProperties; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.security.KeyStore; + +/** + * @author Michele Rastelli + */ +@Dependent +public class ArangoProvider { + + @Produces + public ArangoDB arangoDB(@ConfigProperties final ArangoConfig config) throws Exception { + return new ArangoDB.Builder() + .loadProperties(config) + .sslContext(createSslContext(config)) + .build(); + } + + private static SSLContext createSslContext(ArangoConfig config) throws Exception { + var ks = KeyStore.getInstance(config.getTrustStoreType()); + ks.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(config.getTrustStoreFile()), + config.getTrustStorePassword().toCharArray()); + var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + var sc = SSLContext.getInstance("TLS"); + sc.init(null, tmf.getTrustManagers(), null); + return sc; + } +} diff --git a/src/main/java/io/helidon/examples/quickstart/mp/GreetingResource.java b/src/main/java/com/example/myproject/ArangoResource.java similarity index 53% rename from src/main/java/io/helidon/examples/quickstart/mp/GreetingResource.java rename to src/main/java/com/example/myproject/ArangoResource.java index 0b654ed..e665814 100644 --- a/src/main/java/io/helidon/examples/quickstart/mp/GreetingResource.java +++ b/src/main/java/com/example/myproject/ArangoResource.java @@ -1,20 +1,20 @@ -package io.helidon.examples.quickstart.mp; +package com.example.myproject; import com.arangodb.entity.ArangoDBVersion; +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 javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; @Path("/version") -public class GreetingResource { +public class ArangoResource { private final ArangoService arangoService; @Inject - public GreetingResource(ArangoService arangoService) { + public ArangoResource(ArangoService arangoService) { this.arangoService = arangoService; } @@ -23,5 +23,4 @@ public GreetingResource(ArangoService arangoService) { public ArangoDBVersion getVersion() { return arangoService.getVersion(); } - } diff --git a/src/main/java/io/helidon/examples/quickstart/mp/ArangoService.java b/src/main/java/com/example/myproject/ArangoService.java similarity index 75% rename from src/main/java/io/helidon/examples/quickstart/mp/ArangoService.java rename to src/main/java/com/example/myproject/ArangoService.java index f9ec416..8b7d3dc 100644 --- a/src/main/java/io/helidon/examples/quickstart/mp/ArangoService.java +++ b/src/main/java/com/example/myproject/ArangoService.java @@ -1,10 +1,10 @@ -package io.helidon.examples.quickstart.mp; +package com.example.myproject; import com.arangodb.ArangoDB; import com.arangodb.entity.ArangoDBVersion; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; /** * @author Michele Rastelli diff --git a/src/main/java/com/example/myproject/package-info.java b/src/main/java/com/example/myproject/package-info.java new file mode 100644 index 0000000..4de578c --- /dev/null +++ b/src/main/java/com/example/myproject/package-info.java @@ -0,0 +1,2 @@ + +package com.example.myproject; diff --git a/src/main/java/graal/BrotliSubstitutions.java b/src/main/java/graal/BrotliSubstitutions.java new file mode 100644 index 0000000..ccd245c --- /dev/null +++ b/src/main/java/graal/BrotliSubstitutions.java @@ -0,0 +1,20 @@ +package graal; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; + +public class BrotliSubstitutions { + + @TargetClass(className = "io.netty.handler.codec.compression.Brotli") + static final class Target_io_netty_handler_codec_compression_Brotli { + @Substitute + public static boolean isAvailable() { + return false; + } + + @Substitute + public static void ensureAvailability() throws Throwable { + throw new UnsupportedOperationException(); + } + } +} diff --git a/src/main/java/graal/graal/JdkSubstitutions.java b/src/main/java/graal/graal/JdkSubstitutions.java new file mode 100644 index 0000000..049d946 --- /dev/null +++ b/src/main/java/graal/graal/JdkSubstitutions.java @@ -0,0 +1,98 @@ +package graal.graal; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.InjectAccessors; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import java.io.IOException; +import java.net.URL; +import java.nio.channels.spi.AsynchronousChannelProvider; + +@TargetClass(className = "jdk.internal.loader.URLClassPath$Loader") +final class Target_URLClassPath$Loader { + + @Alias + public Target_URLClassPath$Loader(URL url) { + } +} + +@TargetClass(className = "jdk.internal.loader.URLClassPath$FileLoader") +final class Target_URLClassPath$FileLoader { + + @Alias + public Target_URLClassPath$FileLoader(URL url) throws IOException { + } +} + +@TargetClass(className = "jdk.internal.loader.URLClassPath") +final class Target_jdk_internal_loader_URLClassPath { + + @Substitute + private Target_URLClassPath$Loader getLoader(final URL url) throws IOException { + String file = url.getFile(); + if (file != null && file.endsWith("/")) { + if ("file".equals(url.getProtocol())) { + return (Target_URLClassPath$Loader) (Object) new Target_URLClassPath$FileLoader( + url); + } else { + return new Target_URLClassPath$Loader(url); + } + } else { + // that must be wrong, but JarLoader is deleted by SVM + return (Target_URLClassPath$Loader) (Object) new Target_URLClassPath$FileLoader( + url); + } + } + +} + +@Substitute +@TargetClass(className = "sun.nio.ch.WindowsAsynchronousFileChannelImpl", innerClass = "DefaultIocpHolder") +@Platforms({ Platform.WINDOWS.class }) +final class Target_sun_nio_ch_WindowsAsynchronousFileChannelImpl_DefaultIocpHolder { + + @Alias + @InjectAccessors(DefaultIocpAccessor.class) + static Target_sun_nio_ch_Iocp defaultIocp; +} + +@TargetClass(className = "sun.nio.ch.Iocp") +@Platforms({ Platform.WINDOWS.class }) +final class Target_sun_nio_ch_Iocp { + + @Alias + Target_sun_nio_ch_Iocp(AsynchronousChannelProvider provider, Target_sun_nio_ch_ThreadPool pool) throws IOException { + } + + @Alias + Target_sun_nio_ch_Iocp start() { + return null; + } +} + +@TargetClass(className = "sun.nio.ch.ThreadPool") +@Platforms({ Platform.WINDOWS.class }) +final class Target_sun_nio_ch_ThreadPool { + + @Alias + static Target_sun_nio_ch_ThreadPool createDefault() { + return null; + } +} + +final class DefaultIocpAccessor { + static Target_sun_nio_ch_Iocp get() { + try { + return new Target_sun_nio_ch_Iocp(null, Target_sun_nio_ch_ThreadPool.createDefault()).start(); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + } +} + +class JdkSubstitutions { + +} diff --git a/src/main/java/graal/graal/VertxSubstitutions.java b/src/main/java/graal/graal/VertxSubstitutions.java new file mode 100644 index 0000000..6419ccc --- /dev/null +++ b/src/main/java/graal/graal/VertxSubstitutions.java @@ -0,0 +1,197 @@ +package graal.graal; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import io.netty.handler.ssl.*; +import io.vertx.core.MultiMap; +import io.vertx.core.Promise; +import io.vertx.core.Vertx; +import io.vertx.core.dns.AddressResolverOptions; +import io.vertx.core.eventbus.EventBusOptions; +import io.vertx.core.eventbus.impl.HandlerHolder; +import io.vertx.core.eventbus.impl.HandlerRegistration; +import io.vertx.core.eventbus.impl.MessageImpl; +import io.vertx.core.eventbus.impl.OutboundDeliveryContext; +import io.vertx.core.impl.ContextInternal; +import io.vertx.core.impl.VertxInternal; +import io.vertx.core.impl.resolver.DefaultResolverProvider; +import io.vertx.core.impl.transports.JDKTransport; +import io.vertx.core.net.NetServerOptions; +import io.vertx.core.spi.resolver.ResolverProvider; +import io.vertx.core.spi.transport.Transport; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLException; +import javax.net.ssl.TrustManagerFactory; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +@TargetClass(className = "io.vertx.core.impl.VertxBuilder") +final class Target_io_vertx_core_impl_VertxBuilder { + @Substitute + public static Transport nativeTransport() { + return JDKTransport.INSTANCE; + } +} + +/** + * This substitution forces the usage of the blocking DNS resolver + */ +@TargetClass(className = "io.vertx.core.spi.resolver.ResolverProvider") +final class TargetResolverProvider { + + @Substitute + public static ResolverProvider factory(Vertx vertx, AddressResolverOptions options) { + return new DefaultResolverProvider(); + } +} + +@TargetClass(className = "io.vertx.core.net.OpenSSLEngineOptions") +final class Target_io_vertx_core_net_OpenSSLEngineOptions { + + @Substitute + public static boolean isAvailable() { + return false; + } + + @Substitute + public static boolean isAlpnAvailable() { + return false; + } +} + +@SuppressWarnings("rawtypes") +@TargetClass(className = "io.vertx.core.eventbus.impl.clustered.ClusteredEventBus") +final class Target_io_vertx_core_eventbus_impl_clustered_ClusteredEventBusClusteredEventBus { + + @Substitute + private NetServerOptions getServerOptions() { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + public void start(Promise promise) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + public void close(Promise promise) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + public MessageImpl createMessage(boolean send, boolean isLocal, String address, MultiMap headers, Object body, + String codecName) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + protected void onLocalRegistration(HandlerHolder handlerHolder, Promise promise) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + protected HandlerHolder createHandlerHolder(HandlerRegistration registration, boolean replyHandler, + boolean localOnly, ContextInternal context) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + protected void onLocalUnregistration(HandlerHolder handlerHolder, Promise completionHandler) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + protected void sendOrPub(OutboundDeliveryContext sendContext) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + protected String generateReplyAddress() { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + protected boolean isMessageLocal(MessageImpl msg) { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + ConcurrentMap connections() { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + VertxInternal vertx() { + throw new RuntimeException("Not Implemented"); + } + + @Substitute + EventBusOptions options() { + throw new RuntimeException("Not Implemented"); + } +} + +@TargetClass(className = "io.vertx.core.spi.tls.DefaultSslContextFactory") +final class Target_DefaultSslContextFactory { + + @Alias + private Set enabledCipherSuites; + + @Alias + private List applicationProtocols; + + @Alias + private ClientAuth clientAuth; + + @Substitute + private SslContext createContext(boolean useAlpn, boolean client, KeyManagerFactory kmf, TrustManagerFactory tmf) + throws SSLException { + SslContextBuilder builder; + if (client) { + builder = SslContextBuilder.forClient(); + if (kmf != null) { + builder.keyManager(kmf); + } + } else { + builder = SslContextBuilder.forServer(kmf); + } + Collection cipherSuites = enabledCipherSuites; + builder.sslProvider(SslProvider.JDK); + if (cipherSuites == null || cipherSuites.isEmpty()) { + cipherSuites = Target_io_vertx_core_spi_tls_DefaultJDKCipherSuite.get(); + } + if (tmf != null) { + builder.trustManager(tmf); + } + if (cipherSuites != null && cipherSuites.size() > 0) { + builder.ciphers(cipherSuites); + } + if (useAlpn && applicationProtocols != null && applicationProtocols.size() > 0) { + builder.applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + applicationProtocols)); + } + if (clientAuth != null) { + builder.clientAuth(clientAuth); + } + return builder.build(); + } +} + +@TargetClass(className = "io.vertx.core.spi.tls.DefaultJDKCipherSuite") +final class Target_io_vertx_core_spi_tls_DefaultJDKCipherSuite { + @Alias + static List get() { + return null; + } +} + +class VertxSubstitutions { + +} diff --git a/src/main/java/graal/graal/package-info.java b/src/main/java/graal/graal/package-info.java new file mode 100644 index 0000000..794dbcf --- /dev/null +++ b/src/main/java/graal/graal/package-info.java @@ -0,0 +1,4 @@ +/** + * from io.quarkus:quarkus-vertx:3.10.1 + */ +package graal.graal; diff --git a/src/main/java/graal/netty/EmptyByteBufStub.java b/src/main/java/graal/netty/EmptyByteBufStub.java new file mode 100644 index 0000000..1dc6dab --- /dev/null +++ b/src/main/java/graal/netty/EmptyByteBufStub.java @@ -0,0 +1,33 @@ +package graal.netty; + +import io.netty.util.internal.PlatformDependent; + +import java.nio.ByteBuffer; + +public final class EmptyByteBufStub { + private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocateDirect(0); + private static final long EMPTY_BYTE_BUFFER_ADDRESS; + + static { + long emptyByteBufferAddress = 0; + try { + if (PlatformDependent.hasUnsafe()) { + emptyByteBufferAddress = PlatformDependent.directBufferAddress(EMPTY_BYTE_BUFFER); + } + } catch (Throwable t) { + // Ignore + } + EMPTY_BYTE_BUFFER_ADDRESS = emptyByteBufferAddress; + } + + public static ByteBuffer emptyByteBuffer() { + return EMPTY_BYTE_BUFFER; + } + + public static long emptyByteBufferAddress() { + return EMPTY_BYTE_BUFFER_ADDRESS; + } + + private EmptyByteBufStub() { + } +} diff --git a/src/main/java/graal/netty/graal/HttpContentCompressorSubstitutions.java b/src/main/java/graal/netty/graal/HttpContentCompressorSubstitutions.java new file mode 100644 index 0000000..2489e97 --- /dev/null +++ b/src/main/java/graal/netty/graal/HttpContentCompressorSubstitutions.java @@ -0,0 +1,68 @@ +package graal.netty.graal; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +import java.util.function.BooleanSupplier; + +public class HttpContentCompressorSubstitutions { + + @TargetClass(className = "io.netty.handler.codec.compression.ZstdEncoder", onlyWith = IsZstdAbsent.class) + public static final class ZstdEncoderFactorySubstitution { + + @Substitute + protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception { + throw new UnsupportedOperationException(); + } + + @Substitute + protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) { + throw new UnsupportedOperationException(); + } + + @Substitute + public void flush(final ChannelHandlerContext ctx) { + throw new UnsupportedOperationException(); + } + } + + @Substitute + @TargetClass(className = "io.netty.handler.codec.compression.ZstdConstants", onlyWith = IsZstdAbsent.class) + public static final class ZstdConstants { + + // The constants make calls to com.github.luben.zstd.Zstd so we cut links with that substitution. + + static final int DEFAULT_COMPRESSION_LEVEL = 0; + + static final int MIN_COMPRESSION_LEVEL = 0; + + static final int MAX_COMPRESSION_LEVEL = 0; + + static final int MAX_BLOCK_SIZE = 0; + + static final int DEFAULT_BLOCK_SIZE = 0; + } + + public static class IsZstdAbsent implements BooleanSupplier { + + private boolean zstdAbsent; + + public IsZstdAbsent() { + try { + Class.forName("com.github.luben.zstd.Zstd"); + zstdAbsent = false; + } catch (Exception e) { + // It can be a classloading issue (the library is not available), or a native issue + // (the library for the current OS/arch is not available) + zstdAbsent = true; + } + } + + @Override + public boolean getAsBoolean() { + return zstdAbsent; + } + } +} diff --git a/src/main/java/graal/netty/graal/NettySubstitutions.java b/src/main/java/graal/netty/graal/NettySubstitutions.java new file mode 100644 index 0000000..fb9b8b1 --- /dev/null +++ b/src/main/java/graal/netty/graal/NettySubstitutions.java @@ -0,0 +1,606 @@ +package graal.netty.graal; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import graal.netty.EmptyByteBufStub; +import io.netty.bootstrap.AbstractBootstrapConfig; +import io.netty.bootstrap.ChannelFactory; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.channel.*; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.compression.ZlibCodecFactory; +import io.netty.handler.codec.compression.ZlibWrapper; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http2.Http2Exception; +import io.netty.handler.ssl.*; +import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; +import io.netty.util.concurrent.GlobalEventExecutor; +import io.netty.util.internal.logging.InternalLoggerFactory; +import io.netty.util.internal.logging.JdkLoggerFactory; + +import javax.crypto.NoSuchPaddingException; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; +import javax.net.ssl.TrustManagerFactory; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.security.*; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.util.*; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.function.BooleanSupplier; + +import static io.netty.handler.codec.http.HttpHeaderValues.*; + +/** + * This substitution avoid having loggers added to the build + */ +@TargetClass(className = "io.netty.util.internal.logging.InternalLoggerFactory") +final class Target_io_netty_util_internal_logging_InternalLoggerFactory { + + @Substitute + private static InternalLoggerFactory newDefaultFactory(String name) { + return JdkLoggerFactory.INSTANCE; + } +} + +// SSL +// This whole section is mostly about removing static analysis references to openssl/tcnative + +@TargetClass(className = "io.netty.handler.ssl.SslProvider") +final class Target_io_netty_handler_ssl_SslProvider { + @Substitute + public static boolean isAlpnSupported(final SslProvider provider) { + switch (provider) { + case JDK: + return Target_io_netty_handler_ssl_JdkAlpnApplicationProtocolNegotiator.isAlpnSupported(); + case OPENSSL: + case OPENSSL_REFCNT: + return false; + default: + throw new Error("SslProvider unsupported on Quarkus " + provider); + } + } +} + +@TargetClass(className = "io.netty.handler.ssl.JdkAlpnApplicationProtocolNegotiator") +final class Target_io_netty_handler_ssl_JdkAlpnApplicationProtocolNegotiator { + @Alias + static boolean isAlpnSupported() { + return true; + } +} + +/** + * Hardcode io.netty.handler.ssl.OpenSsl as non-available + */ +@TargetClass(className = "io.netty.handler.ssl.OpenSsl") +final class Target_io_netty_handler_ssl_OpenSsl { + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + private static Throwable UNAVAILABILITY_CAUSE = new RuntimeException("OpenSsl unsupported on Quarkus"); + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + static List DEFAULT_CIPHERS = Collections.emptyList(); + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + static Set AVAILABLE_CIPHER_SUITES = Collections.emptySet(); + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + private static Set AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet(); + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + private static Set AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet(); + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + private static boolean SUPPORTS_KEYMANAGER_FACTORY = false; + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + private static boolean SUPPORTS_OCSP = false; + + @Alias + @RecomputeFieldValue(kind = Kind.FromAlias) + static Set SUPPORTED_PROTOCOLS_SET = Collections.emptySet(); + + @Substitute + public static boolean isAvailable() { + return false; + } + + @Substitute + public static int version() { + return -1; + } + + @Substitute + public static String versionString() { + return null; + } + + @Substitute + public static boolean isCipherSuiteAvailable(String cipherSuite) { + return false; + } +} + +@TargetClass(className = "io.netty.handler.ssl.JdkSslServerContext") +final class Target_io_netty_handler_ssl_JdkSslServerContext { + + @Alias + Target_io_netty_handler_ssl_JdkSslServerContext(Provider provider, + X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, + X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, + KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, + ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, + ClientAuth clientAuth, String[] protocols, boolean startTls, + String keyStore) + throws SSLException { + } +} + +@TargetClass(className = "io.netty.handler.ssl.JdkSslClientContext") +final class Target_io_netty_handler_ssl_JdkSslClientContext { + + @Alias + Target_io_netty_handler_ssl_JdkSslClientContext(Provider sslContextProvider, X509Certificate[] trustCertCollection, + TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, + String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, + CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols, + long sessionCacheSize, long sessionTimeout, String keyStoreType) + throws SSLException { + + } +} + +@TargetClass(className = "io.netty.handler.ssl.SslHandler$SslEngineType") +final class Target_io_netty_handler_ssl_SslHandler$SslEngineType { + + @Alias + public static Target_io_netty_handler_ssl_SslHandler$SslEngineType JDK; + + @Substitute + static Target_io_netty_handler_ssl_SslHandler$SslEngineType forEngine(SSLEngine engine) { + return JDK; + } +} + +@TargetClass(className = "io.netty.handler.ssl.JdkAlpnApplicationProtocolNegotiator$AlpnWrapper") +final class Target_io_netty_handler_ssl_JdkAlpnApplicationProtocolNegotiator_AlpnWrapper { + @Substitute + public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc, + JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) { + return (SSLEngine) (Object) new Target_io_netty_handler_ssl_JdkAlpnSslEngine(engine, applicationNegotiator, + isServer); + } + +} + +@TargetClass(className = "io.netty.handler.ssl.JdkAlpnSslEngine") +final class Target_io_netty_handler_ssl_JdkAlpnSslEngine { + @Alias + Target_io_netty_handler_ssl_JdkAlpnSslEngine(final SSLEngine engine, + final JdkApplicationProtocolNegotiator applicationNegotiator, final boolean isServer) { + + } +} + +@TargetClass(className = "io.netty.handler.ssl.SslContext") +final class Target_io_netty_handler_ssl_SslContext { + + @Substitute + static SslContext newServerContextInternal(SslProvider provider, Provider sslContextProvider, + X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, + X509Certificate[] keyCertChain, + PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, + CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, + ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, String keyStoreType, + Map.Entry, Object>... ctxOptions) throws SSLException { + if (enableOcsp) { + throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider); + } + return (SslContext) (Object) new Target_io_netty_handler_ssl_JdkSslServerContext(sslContextProvider, + trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, + clientAuth, protocols, startTls, keyStoreType); + } + + @Substitute + static SslContext newClientContextInternal(SslProvider provider, Provider sslContextProvider, + X509Certificate[] trustCert, + TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, + KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, + ApplicationProtocolConfig apn, String[] protocols, long sessionCacheSize, long sessionTimeout, + boolean enableOcsp, + String keyStoreType, Map.Entry, Object>... options) throws SSLException { + if (enableOcsp) { + throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider); + } + return (SslContext) (Object) new Target_io_netty_handler_ssl_JdkSslClientContext(sslContextProvider, + trustCert, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, + sessionTimeout, keyStoreType); + } + +} + +@TargetClass(className = "io.netty.handler.ssl.JdkDefaultApplicationProtocolNegotiator") +final class Target_io_netty_handler_ssl_JdkDefaultApplicationProtocolNegotiator { + + @Alias + public static Target_io_netty_handler_ssl_JdkDefaultApplicationProtocolNegotiator INSTANCE; +} + +@TargetClass(className = "io.netty.handler.ssl.JdkSslContext") +final class Target_io_netty_handler_ssl_JdkSslContext { + + @Substitute + static JdkApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config, boolean isServer) { + if (config == null) { + return (JdkApplicationProtocolNegotiator) (Object) Target_io_netty_handler_ssl_JdkDefaultApplicationProtocolNegotiator.INSTANCE; + } + + switch (config.protocol()) { + case NONE: + return (JdkApplicationProtocolNegotiator) (Object) Target_io_netty_handler_ssl_JdkDefaultApplicationProtocolNegotiator.INSTANCE; + case ALPN: + if (isServer) { + // GRAAL RC9 bug: https://github.com/oracle/graal/issues/813 + // switch(config.selectorFailureBehavior()) { + // case FATAL_ALERT: + // return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); + // case NO_ADVERTISE: + // return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); + // default: + // throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + // .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); + // } + SelectorFailureBehavior behavior = config.selectorFailureBehavior(); + if (behavior == SelectorFailureBehavior.FATAL_ALERT) { + return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); + } else if (behavior == SelectorFailureBehavior.NO_ADVERTISE) { + return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); + } else { + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); + } + } else { + switch (config.selectedListenerFailureBehavior()) { + case ACCEPT: + return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); + case FATAL_ALERT: + return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.selectedListenerFailureBehavior()).append(" failure behavior") + .toString()); + } + } + default: + throw new UnsupportedOperationException( + new StringBuilder("JDK provider does not support ").append(config.protocol()) + .append(" protocol") + .toString()); + } + } + +} + +/* + * This one only prints exceptions otherwise we get a useless bogus + * exception message: https://github.com/eclipse-vertx/vert.x/issues/1657 + */ +@TargetClass(className = "io.netty.bootstrap.AbstractBootstrap") +final class Target_io_netty_bootstrap_AbstractBootstrap { + + @Alias + private ChannelFactory channelFactory; + + @Alias + void init(Channel channel) throws Exception { + } + + @Alias + public AbstractBootstrapConfig config() { + return null; + } + + @Substitute + final ChannelFuture initAndRegister() { + Channel channel = null; + try { + channel = channelFactory.newChannel(); + init(channel); + } catch (Throwable t) { + // THE FIX IS HERE: + t.printStackTrace(); + if (channel != null) { + // channel can be null if newChannel crashed (eg SocketException("too many open files")) + channel.unsafe().closeForcibly(); + } + // as the Channel is not registered yet, we need to force the usage of the GlobalEventExecutor + return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t); + } + + ChannelFuture regFuture = config().group().register(channel); + if (regFuture.cause() != null) { + if (channel.isRegistered()) { + channel.close(); + } else { + channel.unsafe().closeForcibly(); + } + } + + // If we are here and the promise is not failed, it's one of the following cases: + // 1) If we attempted registration from the event loop, the registration has been completed at this point. + // i.e. It's safe to attempt bind() or connect() now because the channel has been registered. + // 2) If we attempted registration from the other thread, the registration request has been successfully + // added to the event loop's task queue for later execution. + // i.e. It's safe to attempt bind() or connect() now: + // because bind() or connect() will be executed *after* the scheduled registration task is executed + // because register(), bind(), and connect() are all bound to the same thread. + + return regFuture; + + } +} + +@TargetClass(className = "io.netty.channel.nio.NioEventLoop") +final class Target_io_netty_channel_nio_NioEventLoop { + + @Substitute + private static Queue newTaskQueue0(int maxPendingTasks) { + return new LinkedBlockingDeque<>(); + } +} + +@TargetClass(className = "io.netty.buffer.AbstractReferenceCountedByteBuf") +final class Target_io_netty_buffer_AbstractReferenceCountedByteBuf { + + @Alias + @RecomputeFieldValue(kind = Kind.FieldOffset, name = "refCnt") + private static long REFCNT_FIELD_OFFSET; +} + +@TargetClass(className = "io.netty.util.AbstractReferenceCounted") +final class Target_io_netty_util_AbstractReferenceCounted { + + @Alias + @RecomputeFieldValue(kind = Kind.FieldOffset, name = "refCnt") + private static long REFCNT_FIELD_OFFSET; +} + +// This class is runtime-initialized by NettyProcessor +final class Holder_io_netty_util_concurrent_ScheduledFutureTask { + static final long START_TIME = System.nanoTime(); +} + +@TargetClass(className = "io.netty.util.concurrent.AbstractScheduledEventExecutor") +final class Target_io_netty_util_concurrent_AbstractScheduledEventExecutor { + + // The START_TIME field is kept but not used. + // All the accesses to it have been replaced with Holder_io_netty_util_concurrent_ScheduledFutureTask + + @Substitute + static long initialNanoTime() { + return Holder_io_netty_util_concurrent_ScheduledFutureTask.START_TIME; + } + + @Substitute + static long defaultCurrentTimeNanos() { + return System.nanoTime() - Holder_io_netty_util_concurrent_ScheduledFutureTask.START_TIME; + } +} + +@TargetClass(className = "io.netty.channel.ChannelHandlerMask") +final class Target_io_netty_channel_ChannelHandlerMask { + + // Netty tries to self-optimized itself, but it requires lots of reflection. We disable this behavior and avoid + // misleading DEBUG messages in the log. + @Substitute + private static boolean isSkippable(final Class handlerType, final String methodName, final Class... paramTypes) { + return false; + } +} + +@TargetClass(className = "io.netty.util.internal.NativeLibraryLoader") +final class Target_io_netty_util_internal_NativeLibraryLoader { + + // This method can trick GraalVM into thinking that Classloader#defineClass is getting called + @Substitute + static Class tryToLoadClass(final ClassLoader loader, final Class helper) + throws ClassNotFoundException { + return Class.forName(helper.getName(), false, loader); + } + +} + +@TargetClass(className = "io.netty.buffer.EmptyByteBuf") +final class Target_io_netty_buffer_EmptyByteBuf { + + @Alias + @RecomputeFieldValue(kind = Kind.Reset) + private static ByteBuffer EMPTY_BYTE_BUFFER; + + @Alias + @RecomputeFieldValue(kind = Kind.Reset) + private static long EMPTY_BYTE_BUFFER_ADDRESS; + + @Substitute + public ByteBuffer nioBuffer() { + return EmptyByteBufStub.emptyByteBuffer(); + } + + @Substitute + public ByteBuffer[] nioBuffers() { + return new ByteBuffer[] { EmptyByteBufStub.emptyByteBuffer() }; + } + + @Substitute + public ByteBuffer internalNioBuffer(int index, int length) { + return EmptyByteBufStub.emptyByteBuffer(); + } + + @Substitute + public boolean hasMemoryAddress() { + return EmptyByteBufStub.emptyByteBufferAddress() != 0; + } + + @Substitute + public long memoryAddress() { + if (hasMemoryAddress()) { + return EmptyByteBufStub.emptyByteBufferAddress(); + } else { + throw new UnsupportedOperationException(); + } + } + +} + +@TargetClass(className = "io.netty.handler.codec.http.HttpContentDecompressor") +final class Target_io_netty_handler_codec_http_HttpContentDecompressor { + + @Alias + private boolean strict; + + @Alias + protected ChannelHandlerContext ctx; + + @Substitute + protected EmbeddedChannel newContentDecoder(String contentEncoding) throws Exception { + if (GZIP.contentEqualsIgnoreCase(contentEncoding) || + X_GZIP.contentEqualsIgnoreCase(contentEncoding)) { + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), + ctx.channel().config(), ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); + } + if (DEFLATE.contentEqualsIgnoreCase(contentEncoding) || + X_DEFLATE.contentEqualsIgnoreCase(contentEncoding)) { + final ZlibWrapper wrapper = strict ? ZlibWrapper.ZLIB : ZlibWrapper.ZLIB_OR_NONE; + // To be strict, 'deflate' means ZLIB, but some servers were not implemented correctly. + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), + ctx.channel().config(), ZlibCodecFactory.newZlibDecoder(wrapper)); + } + + // 'identity' or unsupported + return null; + } +} + +@TargetClass(className = "io.netty.handler.codec.http2.DelegatingDecompressorFrameListener") +final class Target_io_netty_handler_codec_http2_DelegatingDecompressorFrameListener { + + @Alias + boolean strict; + + @Substitute + protected EmbeddedChannel newContentDecompressor(ChannelHandlerContext ctx, CharSequence contentEncoding) + throws Http2Exception { + if (!HttpHeaderValues.GZIP.contentEqualsIgnoreCase(contentEncoding) + && !HttpHeaderValues.X_GZIP.contentEqualsIgnoreCase(contentEncoding)) { + if (!HttpHeaderValues.DEFLATE.contentEqualsIgnoreCase(contentEncoding) + && !HttpHeaderValues.X_DEFLATE.contentEqualsIgnoreCase(contentEncoding)) { + return null; + } else { + ZlibWrapper wrapper = this.strict ? ZlibWrapper.ZLIB : ZlibWrapper.ZLIB_OR_NONE; + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), ctx.channel().config(), + new ChannelHandler[] { ZlibCodecFactory.newZlibDecoder(wrapper) }); + } + } else { + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), ctx.channel().config(), + new ChannelHandler[] { ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP) }); + } + } +} + +@TargetClass(className = "io.netty.handler.ssl.SslHandler") +final class Target_SslHandler { + + @Substitute + private void setOpensslEngineSocketFd(Channel c) { + // do nothing. + } +} + +@TargetClass(className = "io.netty.handler.ssl.PemReader") +final class Alias_PemReader { + + @Alias + public static ByteBuf readPrivateKey(File keyFile) { + return null; + } + + @Alias + public static ByteBuf readPrivateKey(InputStream in) throws KeyException { + return null; + } +} + +/** + * If BouncyCastle is not on the classpath, we must not try to read the PEM file using the BouncyCatle PEM reader. + */ +@TargetClass(className = "io.netty.handler.ssl.SslContext", onlyWith = IsBouncyNotThere.class) +final class Target_SslContext { + + @Substitute + protected static PrivateKey toPrivateKey(File keyFile, String keyPassword) throws NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeySpecException, + InvalidAlgorithmParameterException, + KeyException, IOException { + if (keyFile == null) { + return null; + } + + return getPrivateKeyFromByteBuffer(Alias_PemReader.readPrivateKey(keyFile), keyPassword); + } + + @Substitute + protected static PrivateKey toPrivateKey(InputStream keyInputStream, String keyPassword) + throws NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeySpecException, + InvalidAlgorithmParameterException, + KeyException, IOException { + if (keyInputStream == null) { + return null; + } + + return getPrivateKeyFromByteBuffer(Alias_PemReader.readPrivateKey(keyInputStream), keyPassword); + } + + @Alias + private static PrivateKey getPrivateKeyFromByteBuffer(ByteBuf encodedKeyBuf, String keyPassword) + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, + InvalidAlgorithmParameterException, KeyException, IOException { + return null; + } +} + +class IsBouncyNotThere implements BooleanSupplier { + + @Override + public boolean getAsBoolean() { + try { + NettySubstitutions.class.getClassLoader().loadClass("org.bouncycastle.openssl.PEMParser"); + return false; + } catch (Exception e) { + return true; + } + } +} + +class NettySubstitutions { + +} diff --git a/src/main/java/graal/netty/graal/ZLibSubstitutions.java b/src/main/java/graal/netty/graal/ZLibSubstitutions.java new file mode 100644 index 0000000..7017aaa --- /dev/null +++ b/src/main/java/graal/netty/graal/ZLibSubstitutions.java @@ -0,0 +1,66 @@ +package graal.netty.graal; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import io.netty.handler.codec.compression.*; + +/** + * This substitution avoid having jcraft zlib added to the build + */ +@TargetClass(className = "io.netty.handler.codec.compression.ZlibCodecFactory") +final class Target_io_netty_handler_codec_compression_ZlibCodecFactory { + + @Substitute + public static ZlibEncoder newZlibEncoder(int compressionLevel) { + return new JdkZlibEncoder(compressionLevel); + } + + @Substitute + public static ZlibEncoder newZlibEncoder(ZlibWrapper wrapper) { + return new JdkZlibEncoder(wrapper); + } + + @Substitute + public static ZlibEncoder newZlibEncoder(ZlibWrapper wrapper, int compressionLevel) { + return new JdkZlibEncoder(wrapper, compressionLevel); + } + + @Substitute + public static ZlibEncoder newZlibEncoder(ZlibWrapper wrapper, int compressionLevel, int windowBits, int memLevel) { + return new JdkZlibEncoder(wrapper, compressionLevel); + } + + @Substitute + public static ZlibEncoder newZlibEncoder(byte[] dictionary) { + return new JdkZlibEncoder(dictionary); + } + + @Substitute + public static ZlibEncoder newZlibEncoder(int compressionLevel, byte[] dictionary) { + return new JdkZlibEncoder(compressionLevel, dictionary); + } + + @Substitute + public static ZlibEncoder newZlibEncoder(int compressionLevel, int windowBits, int memLevel, byte[] dictionary) { + return new JdkZlibEncoder(compressionLevel, dictionary); + } + + @Substitute + public static ZlibDecoder newZlibDecoder() { + return new JdkZlibDecoder(); + } + + @Substitute + public static ZlibDecoder newZlibDecoder(ZlibWrapper wrapper) { + return new JdkZlibDecoder(wrapper); + } + + @Substitute + public static ZlibDecoder newZlibDecoder(byte[] dictionary) { + return new JdkZlibDecoder(dictionary); + } +} + +class ZLibSubstitutions { + +} diff --git a/src/main/java/graal/netty/package-info.java b/src/main/java/graal/netty/package-info.java new file mode 100644 index 0000000..8b55354 --- /dev/null +++ b/src/main/java/graal/netty/package-info.java @@ -0,0 +1,4 @@ +/** + * from io.quarkus:quarkus-netty:3.10.1 + */ +package graal.netty; diff --git a/src/main/java/io/helidon/examples/quickstart/mp/ArangoConfiguration.java b/src/main/java/io/helidon/examples/quickstart/mp/ArangoConfiguration.java deleted file mode 100644 index 1fe4c39..0000000 --- a/src/main/java/io/helidon/examples/quickstart/mp/ArangoConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.helidon.examples.quickstart.mp; - -import com.arangodb.ArangoDB; - -import javax.enterprise.context.Dependent; -import javax.enterprise.inject.Produces; - -/** - * @author Michele Rastelli - */ -@Dependent -public class ArangoConfiguration { - - @Produces - public ArangoDB arangoDB() { - return new ArangoDB.Builder().password("test").build(); - } - -} diff --git a/src/main/java/io/helidon/examples/quickstart/mp/jsonb/JsonConfig.java b/src/main/java/io/helidon/examples/quickstart/mp/jsonb/JsonConfig.java deleted file mode 100644 index 145a51a..0000000 --- a/src/main/java/io/helidon/examples/quickstart/mp/jsonb/JsonConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.helidon.examples.quickstart.mp.jsonb; - -import javax.json.bind.Jsonb; -import javax.json.bind.JsonbBuilder; -import javax.json.bind.JsonbConfig; -import javax.ws.rs.ext.ContextResolver; -import javax.ws.rs.ext.Provider; - -/** - * @author Michele Rastelli - */ -@Provider -public class JsonConfig implements ContextResolver { - - @Override - public Jsonb getContext(Class aClass) { - return JsonbBuilder - .newBuilder() - .withConfig(new JsonbConfig().withAdapters(new VersionAdapter())) - .build(); - } - -} diff --git a/src/main/java/io/helidon/examples/quickstart/mp/jsonb/VersionAdapter.java b/src/main/java/io/helidon/examples/quickstart/mp/jsonb/VersionAdapter.java deleted file mode 100644 index 0c94bc9..0000000 --- a/src/main/java/io/helidon/examples/quickstart/mp/jsonb/VersionAdapter.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.helidon.examples.quickstart.mp.jsonb; - - -import com.arangodb.entity.ArangoDBVersion; - -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.bind.adapter.JsonbAdapter; - -/** - * @author Michele Rastelli - */ -public class VersionAdapter implements JsonbAdapter { - - @Override - public JsonObject adaptToJson(ArangoDBVersion obj) throws Exception { - return Json.createObjectBuilder() - .add("version", obj.getVersion()) - .add("server", obj.getServer()) - .add("license", obj.getLicense().toString()) - .build(); - } - - @Override - public ArangoDBVersion adaptFromJson(JsonObject obj) throws Exception { - throw new UnsupportedOperationException("not implemented"); - } - -} diff --git a/src/main/java/io/helidon/examples/quickstart/mp/package-info.java b/src/main/java/io/helidon/examples/quickstart/mp/package-info.java deleted file mode 100644 index 95b328a..0000000 --- a/src/main/java/io/helidon/examples/quickstart/mp/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ - -package io.helidon.examples.quickstart.mp; diff --git a/src/main/resources/META-INF/beans.xml b/src/main/resources/META-INF/beans.xml index 5d94aab..fedfc8e 100644 --- a/src/main/resources/META-INF/beans.xml +++ b/src/main/resources/META-INF/beans.xml @@ -1,8 +1,8 @@ - - + + \ No newline at end of file diff --git a/src/main/resources/META-INF/microprofile-config.properties b/src/main/resources/META-INF/microprofile-config.properties index 5e74664..d0e740c 100644 --- a/src/main/resources/META-INF/microprofile-config.properties +++ b/src/main/resources/META-INF/microprofile-config.properties @@ -1,4 +1,10 @@ - # Microprofile server properties server.port=8080 server.host=0.0.0.0 + +adb.hosts=localhost:8529 +adb.password=test +adb.useSsl=true +adb.ssl.trustStoreFile=META-INF/resources/adb.truststore +adb.ssl.trustStorePassword=12345678 +adb.ssl.trustStoreType=pkcs12 diff --git a/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties new file mode 100644 index 0000000..f234ebb --- /dev/null +++ b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties @@ -0,0 +1,8 @@ +Args=\ + -Dio.netty.noUnsafe=true \ + -Dio.netty.leakDetection.level=DISABLED \ + --initialize-at-build-time=\ + com.example.myproject,\ + org.slf4j \ + --initialize-at-run-time=\ + io.netty.handler.ssl.JdkSslServerContext diff --git a/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/reflect-config.json b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/reflect-config.json new file mode 100644 index 0000000..5710092 --- /dev/null +++ b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/reflect-config.json @@ -0,0 +1,6 @@ +[ + { + "name": "com.arangodb.config.HostDescription[]", + "unsafeAllocated": true + } +] \ No newline at end of file diff --git a/src/main/resources/META-INF/native-image/reflect-config.json b/src/main/resources/META-INF/native-image/reflect-config.json deleted file mode 100644 index fe51488..0000000 --- a/src/main/resources/META-INF/native-image/reflect-config.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/src/main/resources/META-INF/resources/adb.truststore b/src/main/resources/META-INF/resources/adb.truststore new file mode 100644 index 0000000000000000000000000000000000000000..e683a48b8a25067c921385081a3a930eae74f05a GIT binary patch literal 2251 zcmchYc{J1w7sux}E5;y8B}*YomhrQUl4Zh33fZ&o%D!YgWO-yNOR|<_MwZAv^b|$1 z4p~c&WULXdElUw2YK+JGyyv{{b58%i=iKif_w&a+_k8a?_p;VlYY+$odLZC$akyT0 z4Y(Fa^b8>$pwM`R4<`hI06-Fa59C5}$RPnZAPYSN00;=21pnMR(%M&}Km!(L7TSc* z=$^fFKa5!fuSahq`Sr?``myydFdA9qeJmmU%K3y1N=h%0vMB{%-vm;*#xs}G*+Y{B z1BAKeQf>IA?PRq(J09eo^7pmNV*73U_o12+&ZolmB6Odb@>Fv{X(@(B&7|!Q&6~bh zU|rD7uu*l}%BNB0Av&LZ-NA^wVP{Q~p-e|fe2mM?9(V)l-=NHZtmjlR;JnoZbH^6;I2x zuKt3aE+TJ;G@`t`#4Z| zV(PfByq(zoF>?>64;uFPiCYl_4(UEV+D-vu&?Jv`z6`JIaJVF^`$I8JT_~CR`ybak zs|<83L@1XJ|Mr!_Q3QAL3|g?ZRM@|pu~QU#U*3Mh?)hN;38dZdz9M3$N&-hCbUC!W zy6W}rjrOyXh{!1Y!q5#`l;yjxpd_($j6&bFalp7%>|w*rD8?u$Dh& zhnSbYn_C9^KZI4oO|C@uU;DM zeKFHuyIJkq3qz`NinbLonP@6!SM5oD^KM7--m1mebq!*|XLSFzd1@6ByH*gJvOXod zH(Fa0OMrFT9^zUL3W;j}s@jGgH(}Ld$d13z1c5n|g z#CZC9>E{QEdUS@gVr4$eW#)5!Fvef**m+kO1IeTQTkGnF*;IXR#@P^h>uB1?T8f9l zr7nuXJP=c;1XRnGLp;L^qGVuR?(%y3 zBiXKS^_-a7&Y+XIiSqrZG|eVmJ@Yauyy9v<2k%l1o2_D#SyFQ9DZwvLIi{<~&y2e| z*c&;Uk#49GV{c=HXX)`R1nH?@$Cv3G?s`F>?XWK2phUwn8+Z>HZX#f`9DGwFBcuQa z6Ksuo$<(Ph+Z!V9>&Y%Um2N{yOPy5o9}FXPf`6hU9@10%d#=vbCzn<`|9u=0Hdq{} z4uQa8KoTqxBthK^VNd`Hg@=Q+&L9TKE*p0t?mGqm&0z-(P=n;%EsHAidXK+eN>UKvkDxea0 zp#P-*_kKu#_&+T_vtC@ko6OJq($nC3Il0R9b)`T|= z(TxpI;UvM~h;ya`j%K$|DveUkqwOgxNgW`~(B`skW_svLblMZd>t(7~!=6F@g`yRh zy~z;$fyd*DmFg$PXLh0{VrXUhDcn#P00D}{z~i9E!7N3%;D_P-?KS)7I!>)kVlVg? zCil$0Y`yt5{huZt?A3vZ07N{{S9^WVja*wIE@lvVMTo9J=QQJLe0*qjRXJ9<+`E4);>i4nt=K)EXsJ@Ens#;)OFz`Z~h}JB90br*0qe?J@UWS#m<`(ucTBh(~WY zT&qusDCN_NPebRa37L7#jufzt-IZ~Y0Fs64s48}{7E*XyrWW9KvG9JHWT9Luz zG78>gPEO>WFbehVA~h|BOCn7Dn0iJ@Vu^MxM|7z9?a7_m(|c`x0-q`#d>rb?oD+4F zL~7~s-r&?vRV+qho|h!e+L~La@@Qp~zfF1($h`xXcX)*5h6zn^@?GOf`Rr7t&~Bju mlH*f^c*Ep6%5+rI!$=hPYi literal 0 HcmV?d00001 diff --git a/src/main/resources/logging.properties b/src/main/resources/logging.properties index cd238eb..ffad43d 100644 --- a/src/main/resources/logging.properties +++ b/src/main/resources/logging.properties @@ -3,7 +3,7 @@ # For more information see $JAVA_HOME/jre/lib/logging.properties # Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler +handlers=io.helidon.logging.jul.HelidonConsoleHandler # HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n @@ -11,9 +11,10 @@ java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$ # 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/src/test/java/com/example/myproject/MainTest.java b/src/test/java/com/example/myproject/MainTest.java new file mode 100644 index 0000000..16608b9 --- /dev/null +++ b/src/test/java/com/example/myproject/MainTest.java @@ -0,0 +1,43 @@ +package com.example.myproject; + +import io.helidon.microprofile.testing.junit5.AddConfig; +import jakarta.ws.rs.core.Response; +import jakarta.json.JsonObject; +import jakarta.inject.Inject; +import jakarta.ws.rs.client.WebTarget; + +import io.helidon.microprofile.testing.junit5.HelidonTest; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +abstract class MainTest { + + @Inject + private WebTarget target; + + @Test + void testVersionEndpoint() { + Response response = target.path("/version") + .request() + .get(); + + assertThat(response.getStatus()).isEqualTo(200); + + String server = response + .readEntity(JsonObject.class) + .getString("server"); + + assertThat(server).isEqualTo("arango"); + } +} + +@HelidonTest +@AddConfig(key = "adb.protocol", value = "HTTP_JSON") +class HttpJsonGreetingResourceTest extends MainTest { +} + +@HelidonTest +@AddConfig(key = "adb.protocol", value = "HTTP2_JSON") +class Http2JsonGreetingResourceTest extends MainTest { +} diff --git a/src/test/java/io/helidon/examples/quickstart/mp/MainIntegrationTest.java b/src/test/java/io/helidon/examples/quickstart/mp/MainIntegrationTest.java deleted file mode 100644 index ca56df5..0000000 --- a/src/test/java/io/helidon/examples/quickstart/mp/MainIntegrationTest.java +++ /dev/null @@ -1,27 +0,0 @@ - -package io.helidon.examples.quickstart.mp; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import javax.json.JsonObject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; - -class MainIntegrationTest { - - @Test - void testVersionEndpoint() { - Client client = ClientBuilder.newClient(); - - JsonObject jsonVersion = client - .target(getConnectionString("/version")) - .request() - .get(JsonObject.class); - Assertions.assertEquals("arango", jsonVersion.getString("server")); - } - - private String getConnectionString(String path) { - return "http://localhost:8081" + path; - } -} diff --git a/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java b/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java deleted file mode 100644 index a2df743..0000000 --- a/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java +++ /dev/null @@ -1,44 +0,0 @@ - -package io.helidon.examples.quickstart.mp; - -import io.helidon.microprofile.server.Server; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import javax.enterprise.inject.se.SeContainer; -import javax.enterprise.inject.spi.CDI; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; - -class MainTest { - private static Server server; - - @BeforeAll - public static void startTheServer() throws Exception { - server = Server.create().start(); - } - - @Test - void testVersionEndpoint() { - Client client = ClientBuilder.newClient(); - - JsonObject jsonVersion = client - .target(getConnectionString("/version")) - .request() - .get(JsonObject.class); - Assertions.assertEquals("arango", jsonVersion.getString("server")); - } - - @AfterAll - static void destroyClass() { - CDI current = CDI.current(); - ((SeContainer) current).close(); - } - - private String getConnectionString(String path) { - return "http://localhost:" + server.port() + path; - } -} diff --git a/src/test/resources/META-INF/microprofile-config.properties b/src/test/resources/META-INF/microprofile-config.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/application-test.yaml b/src/test/resources/application-test.yaml new file mode 100644 index 0000000..94f3451 --- /dev/null +++ b/src/test/resources/application-test.yaml @@ -0,0 +1,2 @@ +security: + enabled: false \ No newline at end of file From 12dd748044fc3e8fdeb63231452aabfb059c41c4 Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Tue, 4 Jun 2024 14:37:28 +0200 Subject: [PATCH 2/9] shaded profile --- .github/workflows/maven.yml | 9 ++- README.md | 8 ++ pom.xml | 75 ++++++++++++++++--- .../java/graal/BrotliSubstitutions.java | 0 .../java/graal/graal/JdkSubstitutions.java | 0 .../java/graal/graal/VertxSubstitutions.java | 0 .../java/graal/graal/package-info.java | 0 .../java/graal/netty/EmptyByteBufStub.java | 0 .../HttpContentCompressorSubstitutions.java | 0 .../graal/netty/graal/NettySubstitutions.java | 0 .../graal/netty/graal/ZLibSubstitutions.java | 0 .../java/graal/netty/package-info.java | 0 12 files changed, 80 insertions(+), 12 deletions(-) rename src/{main => native}/java/graal/BrotliSubstitutions.java (100%) rename src/{main => native}/java/graal/graal/JdkSubstitutions.java (100%) rename src/{main => native}/java/graal/graal/VertxSubstitutions.java (100%) rename src/{main => native}/java/graal/graal/package-info.java (100%) rename src/{main => native}/java/graal/netty/EmptyByteBufStub.java (100%) rename src/{main => native}/java/graal/netty/graal/HttpContentCompressorSubstitutions.java (100%) rename src/{main => native}/java/graal/netty/graal/NettySubstitutions.java (100%) rename src/{main => native}/java/graal/netty/graal/ZLibSubstitutions.java (100%) rename src/{main => native}/java/graal/netty/package-info.java (100%) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 69bd72b..37a1d65 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -8,6 +8,13 @@ jobs: timeout-minutes: 10 runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shaded: + - 'true' + - 'false' + steps: - uses: actions/checkout@v2 - uses: graalvm/setup-graalvm@v1 @@ -26,7 +33,7 @@ jobs: - name: test run: mvn test - name: package-native - run: mvn -Pnative-image package + run: mvn -Pnative-image -Dshaded=${{matrix.shaded}} package - name: start-native run: ./target/arango-helidon-native-example & - name: wait diff --git a/README.md b/README.md index 7bc8cbd..c172244 100644 --- a/README.md +++ b/README.md @@ -39,3 +39,11 @@ You can then execute your native executable with: ``` ./target/arango-helidon-native-example ``` + +## Building a Native Image with the shaded driver + +You can build a native binary using Maven as follows: + +``` +mvn -Pnative-image package -DskipTests -Dshaded +``` diff --git a/pom.xml b/pom.xml index 004f80b..e9d25c4 100644 --- a/pom.xml +++ b/pom.xml @@ -13,18 +13,11 @@ arango-helidon-native-example 1.0-SNAPSHOT + + 7.7.0-SNAPSHOT + + - - com.arangodb - arangodb-java-driver - 7.7.0-SNAPSHOT - - - org.graalvm.sdk - graal-sdk - 24.0.1 - provided - io.helidon.microprofile.bundles helidon-microprofile-core @@ -88,4 +81,64 @@ + + + + plain + + + !shaded + + + + + com.arangodb + arangodb-java-driver + ${adb.version} + + + org.graalvm.sdk + graal-sdk + 24.0.1 + provided + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + generate-sources + + add-source + + + + ${project.basedir}/src/native/java + + + + + + + + + + shaded + + + shaded + + + + + com.arangodb + arangodb-java-driver-shaded + ${adb.version} + + + + diff --git a/src/main/java/graal/BrotliSubstitutions.java b/src/native/java/graal/BrotliSubstitutions.java similarity index 100% rename from src/main/java/graal/BrotliSubstitutions.java rename to src/native/java/graal/BrotliSubstitutions.java diff --git a/src/main/java/graal/graal/JdkSubstitutions.java b/src/native/java/graal/graal/JdkSubstitutions.java similarity index 100% rename from src/main/java/graal/graal/JdkSubstitutions.java rename to src/native/java/graal/graal/JdkSubstitutions.java diff --git a/src/main/java/graal/graal/VertxSubstitutions.java b/src/native/java/graal/graal/VertxSubstitutions.java similarity index 100% rename from src/main/java/graal/graal/VertxSubstitutions.java rename to src/native/java/graal/graal/VertxSubstitutions.java diff --git a/src/main/java/graal/graal/package-info.java b/src/native/java/graal/graal/package-info.java similarity index 100% rename from src/main/java/graal/graal/package-info.java rename to src/native/java/graal/graal/package-info.java diff --git a/src/main/java/graal/netty/EmptyByteBufStub.java b/src/native/java/graal/netty/EmptyByteBufStub.java similarity index 100% rename from src/main/java/graal/netty/EmptyByteBufStub.java rename to src/native/java/graal/netty/EmptyByteBufStub.java diff --git a/src/main/java/graal/netty/graal/HttpContentCompressorSubstitutions.java b/src/native/java/graal/netty/graal/HttpContentCompressorSubstitutions.java similarity index 100% rename from src/main/java/graal/netty/graal/HttpContentCompressorSubstitutions.java rename to src/native/java/graal/netty/graal/HttpContentCompressorSubstitutions.java diff --git a/src/main/java/graal/netty/graal/NettySubstitutions.java b/src/native/java/graal/netty/graal/NettySubstitutions.java similarity index 100% rename from src/main/java/graal/netty/graal/NettySubstitutions.java rename to src/native/java/graal/netty/graal/NettySubstitutions.java diff --git a/src/main/java/graal/netty/graal/ZLibSubstitutions.java b/src/native/java/graal/netty/graal/ZLibSubstitutions.java similarity index 100% rename from src/main/java/graal/netty/graal/ZLibSubstitutions.java rename to src/native/java/graal/netty/graal/ZLibSubstitutions.java diff --git a/src/main/java/graal/netty/package-info.java b/src/native/java/graal/netty/package-info.java similarity index 100% rename from src/main/java/graal/netty/package-info.java rename to src/native/java/graal/netty/package-info.java From e2b97ac3fe722d288825d23260414924773a765c Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Tue, 4 Jun 2024 15:28:41 +0200 Subject: [PATCH 3/9] CI: print deps tree --- .github/workflows/maven.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 37a1d65..ab77cd8 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -26,6 +26,8 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Info run: mvn -version + - name: Deps tree + run: mvn dependency:tree -Dshaded=${{matrix.shaded}} - name: Start Database run: ./docker/start_db.sh env: From 6e36a6f8f0395fe9bc3c0205cf13a765c2294cbf Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Wed, 5 Jun 2024 10:56:46 +0200 Subject: [PATCH 4/9] fixed beans scope --- src/main/java/com/example/myproject/ArangoProvider.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/myproject/ArangoProvider.java b/src/main/java/com/example/myproject/ArangoProvider.java index 8217247..c916b35 100644 --- a/src/main/java/com/example/myproject/ArangoProvider.java +++ b/src/main/java/com/example/myproject/ArangoProvider.java @@ -1,7 +1,9 @@ package com.example.myproject; import com.arangodb.ArangoDB; +import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Disposes; import jakarta.enterprise.inject.Produces; import org.eclipse.microprofile.config.inject.ConfigProperties; @@ -12,10 +14,11 @@ /** * @author Michele Rastelli */ -@Dependent +@ApplicationScoped public class ArangoProvider { @Produces + @Dependent public ArangoDB arangoDB(@ConfigProperties final ArangoConfig config) throws Exception { return new ArangoDB.Builder() .loadProperties(config) @@ -23,6 +26,10 @@ public ArangoDB arangoDB(@ConfigProperties final ArangoConfig config) throws Exc .build(); } + public void close(@Disposes ArangoDB arangoDB) { + arangoDB.shutdown(); + } + private static SSLContext createSslContext(ArangoConfig config) throws Exception { var ks = KeyStore.getInstance(config.getTrustStoreType()); ks.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(config.getTrustStoreFile()), From 826eb53547786926c19ed115a80c2e28a602ffb2 Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Wed, 5 Jun 2024 16:46:46 +0200 Subject: [PATCH 5/9] added snapshot repository --- pom.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pom.xml b/pom.xml index e9d25c4..8ff5fa7 100644 --- a/pom.xml +++ b/pom.xml @@ -141,4 +141,18 @@ + + + + arangodb-snapshots + https://oss.sonatype.org/content/groups/staging + + true + + + false + + + + From 9032486100c1f1923d8b02c010f227b1eae3d037 Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Wed, 5 Jun 2024 22:58:41 +0200 Subject: [PATCH 6/9] updated native image configuration --- .../native-image.properties | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties index f234ebb..a2b949a 100644 --- a/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties +++ b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties @@ -3,6 +3,37 @@ Args=\ -Dio.netty.leakDetection.level=DISABLED \ --initialize-at-build-time=\ com.example.myproject,\ - org.slf4j \ + org.slf4j,\ + io.netty \ --initialize-at-run-time=\ - io.netty.handler.ssl.JdkSslServerContext + io.netty.buffer.PooledByteBufAllocator,\ + io.netty.buffer.ByteBufAllocator,\ + io.netty.buffer.ByteBufUtil,\ + io.netty.buffer.AbstractReferenceCountedByteBuf,\ + io.netty.handler.ssl.JdkSslServerContext,\ + io.netty.handler.codec.compression.BrotliDecoder,\ + io.netty.handler.codec.compression.ZstdConstants,\ + io.netty.handler.codec.http2.Http2CodecUtil,\ + io.netty.handler.codec.http2.Http2ClientUpgradeCodec,\ + io.netty.handler.codec.http2.Http2ConnectionHandler,\ + io.netty.handler.codec.http2.DefaultHttp2FrameWriter,\ + io.netty.handler.codec.http.HttpObjectEncoder,\ + io.netty.handler.codec.http.websocketx.WebSocket00FrameEncoder,\ + io.netty.handler.codec.http.websocketx.extensions.compression.DeflateDecoder,\ + io.netty.util.AbstractReferenceCounted,\ + io.netty.util.concurrent.GlobalEventExecutor,\ + io.netty.util.concurrent.ImmediateEventExecutor,\ + io.netty.util.concurrent.ScheduledFutureTask,\ + io.netty.util.internal.ThreadLocalRandom,\ + io.netty.util.NetUtilSubstitutions$NetUtilLocalhost4LazyHolder,\ + io.netty.util.NetUtilSubstitutions$NetUtilLocalhost6LazyHolder,\ + io.netty.util.NetUtilSubstitutions$NetUtilLocalhostLazyHolder,\ + io.netty.util.NetUtilSubstitutions$NetUtilNetworkInterfacesLazyHolder,\ + io.netty.handler.ssl.util.ThreadLocalInsecureRandom,\ + io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider,\ + io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder,\ + io.netty.resolver.dns.DnsNameResolver,\ + io.netty.resolver.HostsFileEntriesResolver,\ + io.netty.resolver.dns.ResolvConf$ResolvConfLazy,\ + io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider,\ + io.vertx.core.buffer.impl.VertxByteBufAllocator From fc15d347c263de0b05a81abd52d3ea8e7f7f3b37 Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Thu, 6 Jun 2024 10:44:15 +0200 Subject: [PATCH 7/9] updated native image configuration --- .../arango-helidon-native-example/native-image.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties index a2b949a..718b493 100644 --- a/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties +++ b/src/main/resources/META-INF/native-image/com/arangodb/arango-helidon-native-example/native-image.properties @@ -20,6 +20,9 @@ Args=\ io.netty.handler.codec.http.HttpObjectEncoder,\ io.netty.handler.codec.http.websocketx.WebSocket00FrameEncoder,\ io.netty.handler.codec.http.websocketx.extensions.compression.DeflateDecoder,\ + io.netty.handler.codec.http2.CleartextHttp2ServerUpgradeHandler,\ + io.netty.handler.codec.http2.Http2ServerUpgradeCodec,\ + io.netty.handler.pcap.PcapWriteHandler$WildcardAddressHolder,\ io.netty.util.AbstractReferenceCounted,\ io.netty.util.concurrent.GlobalEventExecutor,\ io.netty.util.concurrent.ImmediateEventExecutor,\ From 31a4e47db4a5bf14e6b45481a22bd9b3f34cd262 Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Thu, 6 Jun 2024 15:39:09 +0200 Subject: [PATCH 8/9] fixed activation of shaded profile --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8ff5fa7..d8dc8ff 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,8 @@ plain - !shaded + shaded + !true @@ -130,6 +131,7 @@ shaded + true From da1a18308d9aa7f08846c68a01a4094e838918e5 Mon Sep 17 00:00:00 2001 From: Michele Rastelli Date: Fri, 7 Jun 2024 16:01:26 +0200 Subject: [PATCH 9/9] updated java driver 7.7.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d8dc8ff..80accb5 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ 1.0-SNAPSHOT - 7.7.0-SNAPSHOT + 7.7.0