From b0e8c4f85ec10f66db3ef412f5dfc1c4f537dcb6 Mon Sep 17 00:00:00 2001 From: linghengqian Date: Wed, 26 Jul 2023 22:03:43 +0800 Subject: [PATCH] Update the version of GraalVM used by ShardingSphere Proxy Native to 23.0.0 --- .github/workflows/nightly-build.yml | 6 +- distribution/proxy-native/Dockerfile | 10 +- distribution/proxy-native/access-filter.json | 3 +- distribution/proxy-native/pom.xml | 3 +- .../src/main/release-docs/LICENSE | 3 +- .../proxy/src/main/release-docs/LICENSE | 2 +- .../startup/graalvm-native-image.cn.md | 37 ++-- .../startup/graalvm-native-image.en.md | 55 +++--- infra/expr/core/pom.xml | 10 +- .../core/InlineExpressionParserFactory.java | 2 +- infra/expr/espresso/pom.xml | 34 ---- .../EspressoInlineExpressionParser.java | 161 ++++++++++++++---- pom.xml | 4 +- 13 files changed, 202 insertions(+), 128 deletions(-) diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index 52e2084be5dd37..e3a7a0a598ee67 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -108,7 +108,7 @@ jobs: build-proxy-native-image: if: github.repository == 'apache/shardingsphere' name: Build GraalVM Native Image - timeout-minutes: 90 + timeout-minutes: 60 permissions: contents: read packages: write @@ -119,8 +119,8 @@ jobs: ref: ${{ inputs.commit-id }} - uses: graalvm/setup-graalvm@v1 with: - version: '22.3.1' - java-version: '17' + java-version: '17.0.7' + distribution: 'graalvm-community' components: 'espresso,native-image' github-token: ${{ secrets.GITHUB_TOKEN }} cache: 'maven' diff --git a/distribution/proxy-native/Dockerfile b/distribution/proxy-native/Dockerfile index 4578fd982d1eaf..a21b8b0db9ee40 100644 --- a/distribution/proxy-native/Dockerfile +++ b/distribution/proxy-native/Dockerfile @@ -22,18 +22,14 @@ ENV LOCAL_PATH /opt/shardingsphere-proxy-native ADD target/${APP_NAME}.tar.gz /opt RUN mv /opt/${APP_NAME} ${LOCAL_PATH} -FROM oraclelinux:9-slim +FROM ghcr.io/graalvm/graalvm-community:17.0.7-ol9 MAINTAINER ShardingSphere "dev@shardingsphere.apache.org" ARG NATIVE_IMAGE_NAME ENV LOCAL_PATH /opt/shardingsphere-proxy-native -ENV JAVA_HOME "/opt/graalvm-ce-java17-22.3.1" -ENV PATH "$JAVA_HOME/bin:$PATH" -RUN microdnf install gzip -y && \ - bash <(curl -sL https://get.graalvm.org/jdk) --to "/opt" -c espresso graalvm-ce-java17-22.3.1 && \ - $JAVA_HOME/bin/gu remove native-image && \ - microdnf clean all +RUN $JAVA_HOME/bin/gu install espresso && \ + $JAVA_HOME/bin/gu remove native-image COPY --from=prepare ${LOCAL_PATH} ${LOCAL_PATH} ENTRYPOINT ${LOCAL_PATH}/${NATIVE_IMAGE_NAME} 3307 ${LOCAL_PATH}/conf "0.0.0.0" false diff --git a/distribution/proxy-native/access-filter.json b/distribution/proxy-native/access-filter.json index 64bb113557fa14..6b41a36a4aecc8 100644 --- a/distribution/proxy-native/access-filter.json +++ b/distribution/proxy-native/access-filter.json @@ -5,8 +5,7 @@ {"excludeClasses": "org.mariadb.jdbc.**"}, {"excludeClasses": "com.mysql.jdbc.**"}, {"excludeClasses": "org.apache.commons.dbcp2.**"}, - {"excludeClasses": "org.apache.shardingsphere.test.fixture.jdbc.**"}, - {"excludeClasses": "org.apache.shardingsphere.data.pipeline.core.sqlbuilder.H2PipelineSQLBuilder"} + {"excludeClasses": "org.apache.shardingsphere.test.fixture.jdbc.**"} ], "regexRules": [ {"excludeClasses": ".*Fixture*.*"} diff --git a/distribution/proxy-native/pom.xml b/distribution/proxy-native/pom.xml index 9ef6fa01c7fef1..74930be3d7b7f5 100644 --- a/distribution/proxy-native/pom.xml +++ b/distribution/proxy-native/pom.xml @@ -68,7 +68,7 @@ release.native - 22.3.1 + 23.0.1 true true true @@ -98,6 +98,7 @@ true --language:java + -H:+AllowDeprecatedBuilderClassesOnImageClasspath --report-unsupported-elements-at-runtime diff --git a/distribution/proxy-native/src/main/release-docs/LICENSE b/distribution/proxy-native/src/main/release-docs/LICENSE index 1e70e55656258b..8aa0c70bbbd26c 100644 --- a/distribution/proxy-native/src/main/release-docs/LICENSE +++ b/distribution/proxy-native/src/main/release-docs/LICENSE @@ -368,4 +368,5 @@ UPL licenses The following components are provided under the UPL License. See project link for details. The text of each license is also included at licenses/LICENSE-[project].txt. - truffle-api 22.3.1: http://www.graalvm.org/, UPL + graal-sdk 23.0.1: /~https://github.com/oracle/graal, UPL 1.0 + truffle-api 23.0.1: /~https://github.com/oracle/graal/tree/master/truffle, UPL 1.0 diff --git a/distribution/proxy/src/main/release-docs/LICENSE b/distribution/proxy/src/main/release-docs/LICENSE index 8ff1ee83673e6b..5210fc617ffa9a 100644 --- a/distribution/proxy/src/main/release-docs/LICENSE +++ b/distribution/proxy/src/main/release-docs/LICENSE @@ -380,5 +380,5 @@ UPL licenses The following components are provided under the UPL License. See project link for details. The text of each license is also included at licenses/LICENSE-[project].txt. - graal-sdk 21.2.0: /~https://github.com/oracle/graal/tree/master/sdk, UPL 1.0 + graal-sdk 21.2.0: /~https://github.com/oracle/graal, UPL 1.0 truffle-api 21.2.0: /~https://github.com/oracle/graal/tree/master/truffle, UPL 1.0 diff --git a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md index c0e5f29ef3e0d6..741cdb74345eeb 100644 --- a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md +++ b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md @@ -11,7 +11,7 @@ weight = 2 ## 注意事项 - ShardingSphere Proxy 尚未准备好与 GraalVM Native Image 集成。 - 其在 /~https://github.com/apache/shardingsphere/pkgs/container/shardingsphere-proxy-native 存在每夜构建。 + Proxy 的 Native Image 产物在 /~https://github.com/apache/shardingsphere/pkgs/container/shardingsphere-proxy-native 存在每夜构建。 假设存在包含`server.yaml` 的 `conf` 文件夹为 `./custom/conf`,你可通过如下的 `docker-compose.yml` 文件进行测试。 ```yaml @@ -30,8 +30,7 @@ services: 应当在 /~https://github.com/oracle/graalvm-reachability-metadata 打开新的 issue , 并提交包含 ShardingSphere 自身或依赖的第三方库缺失的 GraalVM Reachability Metadata 的 PR。 -- ShardingSphere 的 master 分支尚未准备好处理 Native Image 中的单元测试, - 需要等待 Junit 5 Platform 的集成,你总是需要在构建 GraalVM Native Image 的过程中, +- ShardingSphere 的 master 分支尚未准备好处理 Native Image 中的单元测试, 你总是需要在构建 GraalVM Native Image 的过程中, 加上特定于 `GraalVM Native Build Tools` 的 `-DskipNativeTests` 或 `-DskipTests` 参数跳过 Native Image 中的单元测试。 - 如下 3 个算法类由于涉及到 GraalVM Truffle Espresso 不方便在 host JVM 和 guest JVM 之间交互的 `groovy.lang.Closure` @@ -43,7 +42,7 @@ services: - 当前阶段,GraalVM Native Image 形态的 ShardingSphere Proxy 处于混合 AOT ( GraalVM Native Image ) 和 JIT ( GraalVM Truffle Espresso ) 运行的阶段。由于 /~https://github.com/oracle/graal/issues/4555 尚未关闭,GraalVM Truffle Espresso 运行需要的 `.so` 文件并不会进入 GraalVM Native Image 内。因此如果你需要在 Docker Image 外运行 ShardingSphere Proxy - Native 的二进制文件,你需要确保系统环境变量 `JAVA_HOME` 指向 GraalVM 的 `bin` 目录,并且此 GraalVM + Native 的二进制文件,你需要确保系统环境变量 `JAVA_HOME` 指向 GraalVM 的目录,并且此 GraalVM 实例已经通过 `GraalVM Updater` 安装了 `espresso` 组件。 - 本节假定处于 Linux(amd64,aarch64), MacOS(amd64)或 Windows(amd64)环境。 @@ -51,12 +50,19 @@ services: ## 前提条件 -1. 根据 https://www.graalvm.org/downloads/ 要求安装和配置 JDK 17 对应的 `GraalVM CE` 或 `GraalVM EE`。 - 同时可以通过 `SDKMAN!` 安装 JDK 17 对应的 `GraalVM CE`。 +1. 根据 https://www.graalvm.org/downloads/ 要求安装和配置 JDK 17 对应的 `GraalVM Community Edition` 或 `Oracle GraalVM`。或者使用 `SDKMAN!`。 -2. 通过 `GraalVM Updater` 工具安装 `native-image` 和 `espresso` 组件。 +```shell +sdk install java 17.0.7-graalce +``` + +2. 通过 `GraalVM Updater` 工具安装 `espresso` 组件。 + +```shell +gu install espresso +``` -3. 根据 https://www.graalvm.org/22.3/reference-manual/native-image/#prerequisites 的要求安装本地工具链。 +3. 根据 https://www.graalvm.org/latest/reference-manual/native-image/#prerequisites 的要求安装本地工具链。 4. 如果需要构建 Docker Image, 确保 `docker-ce` 已安装。 @@ -94,12 +100,12 @@ services: com.mysql mysql-connector-j - 8.0.32 + 8.1.0 org.apache.shardingsphere shardingsphere-sql-translator-jooq-provider - 5.3.1 + 5.4.0 ``` @@ -140,13 +146,12 @@ services: - "3307:3307" ``` -- 如果你不对 Git Source 做任何更改, 上文提及的命令将使用 `oraclelinux:9-slim` 作为 Base Docker Image。 +- 如果你不对 Git Source 做任何更改, 上文提及的命令将使用 `ghcr.io/graalvm/graalvm-community:17.0.7-ol9` 作为 Base Docker Image。 但如果你希望使用 `busybox:glic`,`gcr.io/distroless/base` 或 `scratch` 等更小体积的 Docker Image 作为 Base Docker - Image,你需要根据 https://www.graalvm.org/22.3/reference-manual/native-image/guides/build-static-executables/ 的要求, + Image,你需要根据 https://www.graalvm.org/latest/reference-manual/native-image/guides/build-static-executables/ 的要求, 做为 `pom.xml`的 `native profile` 添加 `-H:+StaticExecutableWithDynamicLibC` 的 `jvmArgs` 等操作。 另请注意,某些第三方依赖将需要在 `Dockerfile` 安装更多系统库,例如 `libdl`。 - 因此请确保根据你的使用情况调整 `distribution/proxy-native` - 下的 `pom.xml` 和 `Dockerfile` 的内容。 + 因此请确保根据你的使用情况调整 `distribution/proxy-native` 下的 `pom.xml` 和 `Dockerfile` 的内容。 # 可观察性 @@ -154,7 +159,7 @@ services: Proxy,其提供的可观察性的能力与 https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-proxy/observability/ 并不一致。 -- 你可以使用 https://www.graalvm.org/22.3/tools/ 提供的一系列命令行工具或可视化工具观察 GraalVM Native Image +- 你可以使用 https://www.graalvm.org/latest/tools/ 提供的一系列命令行工具或可视化工具观察 GraalVM Native Image 的内部行为,并根据其要求使用 VSCode 完成调试工作。 如果你正在使用 IntelliJ IDEA 并且希望调试生成的 GraalVM Native Image,你可以关注 https://blog.jetbrains.com/idea/2022/06/intellij-idea-2022-2-eap-5/#Experimental_GraalVM_Native_Debugger_for_Java @@ -166,7 +171,7 @@ services: - 以下部分采用 `Apache SkyWalking Java Agent` 作为示例,可用于跟踪 GraalVM 社区的对应 issue。 -1. 下载 https://archive.apache.org/dist/skywalking/java-agent/8.12.0/apache-skywalking-java-agent-8.12.0.tgz , +1. 下载 https://dlcdn.apache.org/skywalking/java-agent/8.16.0/apache-skywalking-java-agent-8.16.0.tgz , 并解压到 ShardingSphere Git Source 的 `distribution/proxy-native`。 2. 修改 `distribution/proxy-native/pom.xml` 的 `native profile`, diff --git a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md index 5d37f04ac1fbb9..edf43894b36728 100644 --- a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md +++ b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md @@ -11,8 +11,7 @@ corresponding `Docker Image` through the `native-image` component of `GraalVM`. ## Notice - ShardingSphere Proxy is not yet ready to integrate with GraalVM Native Image. - Fixes documentation for building GraalVM Native Image It exists nightly builds - at /~https://github.com/apache/shardingsphere/pkgs/container/shardingsphere-proxy-native. + Proxy's Native Image artifacts are built nightly at /~https://github.com/apache/shardingsphere/pkgs/container/shardingsphere-proxy-native . Assuming there is a `conf` folder containing `server.yaml` as `./custom/conf`, you can test it with the following `docker-compose.yml` file. @@ -29,12 +28,11 @@ services: ```` - If you find that the build process has missing GraalVM Reachability Metadata, - A new issue should be opened at /~https://github.com/oracle/graalvm-reachability-metadata, - And submit a PR containing GraalVM Reachability Metadata missing from ShardingSphere itself or dependent third-party - libraries. + a new issue should be opened at /~https://github.com/oracle/graalvm-reachability-metadata, + and submit a PR containing GraalVM Reachability Metadata missing from ShardingSphere itself or dependent third-party libraries. - The master branch of ShardingSphere is not yet ready to handle unit tests in Native Image, - Need to wait for the integration of Junit 5 Platform, you always need to build GraalVM Native Image in the process, + you always need to build GraalVM Native Image in the process, Plus `-DskipNativeTests` or `-DskipTests` parameter specific to `GraalVM Native Build Tools` to skip unit tests in Native Image. @@ -48,9 +46,9 @@ services: - At the current stage, ShardingSphere Proxy in GraalVM Native Image is in the stage of mixed AOT ( GraalVM Native Image ) and JIT ( GraalVM Truffle Espresso ) operation. Since /~https://github.com/oracle/graal/issues/4555 has not been closed, the `.so` file required for GraalVM Truffle Espresso to run does not enter the GraalVM Native Image. - So if you need to run ShardingSphere Proxy Native binary files outside the Docker Image, you need to ensure - that the system environment variable `JAVA_HOME` points to the `bin` directory of GraalVM, and this - GraalVM instance already has the `espresso` component installed via the `GraalVM Updater`. + So if you need to run ShardingSphere Proxy outside of Docker Image For Native binaries, + you need to make sure that the system environment variable `JAVA_HOME` points to GraalVM's + directory and this GraalVM instance already has the `espresso` component installed via `GraalVM Updater`. - This section assumes a Linux (amd64, aarch64), MacOS (amd64) or Windows (amd64) environment. If you are on MacOS (aarch64/M1) environment, you need to follow /~https://github.com/oracle/graal/issues/2666 which is @@ -58,12 +56,19 @@ services: ## Premise -1. Install and configure `GraalVM CE` or `GraalVM EE` for JDK 17 according to https://www.graalvm.org/downloads/. - `GraalVM CE` for JDK 17 can also be installed via `SDKMAN!`. +1. Install and configure `GraalVM Community Edition` or `Oracle GraalVM` for JDK 17 according to https://www.graalvm.org/downloads/. Or use `SDKMAN!`. -2. Install the `native-image` and `espresso` component via the `GraalVM Updater` tool. +```shell +sdk install java 17.0.7-graalce +``` + +2. Install the `espresso` component via the `GraalVM Updater` tool. + +```shell +gu install espresso +``` -3. Install the local toolchain as required by https://www.graalvm.org/22.3/reference-manual/native-image/#prerequisites. +3. Install the local toolchain as required by https://www.graalvm.org/latest/reference-manual/native-image/#prerequisites. 4. If you need to build a Docker Image, make sure `docker-ce` is installed. @@ -104,12 +109,12 @@ services: com.mysql mysql-connector-j - 8.0.32 + 8.1.0 org.apache.shardingsphere shardingsphere-sql-translator-jooq-provider - 5.3.1 + 5.4.0 ``` @@ -153,25 +158,23 @@ services: - "3307:3307" ``` -- If you don't make any changes to the Git Source, the commands mentioned above will use `oraclelinux:9-slim` as the +- If you don't make any changes to the Git Source, the commands mentioned above will use `ghcr.io/graalvm/graalvm-community:17.0.7-ol9` as the Base Docker Image. - But if you want to use a smaller Docker Image like `busybox:glic`, `gcr.io/distroless/base` or `scratch` as the Base - Docker Image, you need according - to https://www.graalvm.org/22.3/reference-manual/native-image/guides/build-static-executables/, - Add operations such as `-H:+StaticExecutableWithDynamicLibC` to `jvmArgs` as the `native profile` of `pom.xml`. - Also note that some 3rd party dependencies will require more system libraries such as `libdl` to be installed in + But if you want to use a smaller Docker Image like `busybox:glic`, `gcr.io/distroless/base` or `scratch` as the Base Docker Image, you need according + to https://www.graalvm.org/latest/reference-manual/native-image/guides/build-static-executables/, + add operations such as `-H:+StaticExecutableWithDynamicLibC` to `jvmArgs` as the `native profile` of `pom.xml`. + Also note that some 3rd-party dependencies will require more system libraries such as `libdl` to be installed in the `Dockerfile`. - So make sure to tune `distribution/proxy-native` according to your usage - `pom.xml` and `Dockerfile` below. + So make sure to tune `distribution/proxy-native` according to your usage `pom.xml` and `Dockerfile` below. # Observability - ShardingSphere for GraalVM Native Image form Proxy, which provides observability capabilities with https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-proxy/observability/ - Not consistent. + not consistent. - You can observe GraalVM Native Image using a series of command line tools or visualization tools available - at https://www.graalvm.org/22.3/tools/, and use VSCode to debug it according to its requirements. + at https://www.graalvm.org/latest/tools/, and use VSCode to debug it according to its requirements. If you are using IntelliJ IDEA and want to debug the generated GraalVM Native Image, You can follow https://blog.jetbrains.com/idea/2022/06/intellij-idea-2022-2-eap-5/#Experimental_GraalVM_Native_Debugger_for_Java and its successors. If you are not using Linux, you cannot debug GraalVM Native Image, please pay attention @@ -184,7 +187,7 @@ services: - The following sections use the `Apache SkyWalking Java Agent` as an example, which can be used to track corresponding issues from the GraalVM community. -1. Download https://archive.apache.org/dist/skywalking/java-agent/8.12.0/apache-skywalking-java-agent-8.12.0.tgz and `untar` it +1. Download https://dlcdn.apache.org/skywalking/java-agent/8.16.0/apache-skywalking-java-agent-8.16.0.tgz and `untar` it to `distribution/proxy-native` in ShardingSphere Git Source. 2. Modify the `native profile` of `distribution/proxy-native/pom.xml`, diff --git a/infra/expr/core/pom.xml b/infra/expr/core/pom.xml index fdc41cd673c0db..041a67bbf3f0d1 100644 --- a/infra/expr/core/pom.xml +++ b/infra/expr/core/pom.xml @@ -37,11 +37,11 @@ shardingsphere-infra-expr-hotsopt ${project.version} - - org.apache.shardingsphere - shardingsphere-infra-expr-espresso - ${project.version} - + + + + + org.apache.shardingsphere diff --git a/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java b/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java index b9ca766679fd66..3f71023d82d8a9 100644 --- a/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java +++ b/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java @@ -28,7 +28,7 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class InlineExpressionParserFactory { - // workaround for https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledInNativeImage.html + // workaround for https://junit.org/junit5/docs/5.10.0/api/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledInNativeImage.html private static final boolean IS_SUBSTRATE_VM = "runtime".equals(System.getProperty("org.graalvm.nativeimage.imagecode")); /** diff --git a/infra/expr/espresso/pom.xml b/infra/expr/espresso/pom.xml index 3786c680991364..6ffcb8f35b25bf 100644 --- a/infra/expr/espresso/pom.xml +++ b/infra/expr/espresso/pom.xml @@ -37,12 +37,6 @@ shardingsphere-infra-util ${project.version} - - - org.apache.shardingsphere - shardingsphere-infra-expr-hotsopt - ${project.version} - org.graalvm.truffle @@ -65,27 +59,6 @@ prepare-package - - org.apache.shardingsphere - shardingsphere-infra-expr-spi - ${project.version} - jar - true - - - org.apache.shardingsphere - shardingsphere-infra-util - ${project.version} - jar - true - - - org.apache.shardingsphere - shardingsphere-infra-expr-hotsopt - ${project.version} - jar - true - org.apache.groovy groovy @@ -93,13 +66,6 @@ jar true - - com.google.guava - guava - ${guava.version} - jar - true - true ${project.build.outputDirectory}/espresso-need-libs diff --git a/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java b/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java index d1360b3636a2aa..1b4b53d6e75e67 100644 --- a/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java +++ b/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java @@ -17,20 +17,23 @@ package org.apache.shardingsphere.infra.expr.espresso; +import com.google.common.base.Strings; +import com.google.common.collect.Sets; import groovy.lang.Closure; -import org.apache.shardingsphere.infra.expr.hotsopt.HotspotInlineExpressionParser; +import groovy.lang.GroovyShell; import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser; -import org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.TypeLiteral; import org.graalvm.polyglot.Value; import java.io.File; import java.net.URL; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * Espresso inline expression parser. @@ -39,56 +42,156 @@ public final class EspressoInlineExpressionParser implements InlineExpressionPar private static final String JAVA_CLASSPATH; - private static final String JAVA_HOME; + private static final Context CONTEXT; + + private static final char SPLITTER = ','; static { - JAVA_HOME = System.getenv("JAVA_HOME"); URL resource = Thread.currentThread().getContextClassLoader().getResource("espresso-need-libs"); String dir = null != resource ? resource.getPath() : null; - JAVA_CLASSPATH = Stream.of("groovy.jar", "guava.jar", "shardingsphere-infra-expr-hotsopt.jar", "shardingsphere-infra-expr-spi.jar", "shardingsphere-infra-util.jar") - .map(each -> dir + File.separator + each).collect(Collectors.joining(":")); + JAVA_CLASSPATH = dir + File.separator + "groovy.jar"; + CONTEXT = createContext(); } @Override public String handlePlaceHolder(final String inlineExpression) { - try (Context context = createContext()) { - return createInlineExpressionParser(context).invokeMember("handlePlaceHolder", inlineExpression).asString(); - } + return inlineExpression.contains("$->{") ? inlineExpression.replaceAll("\\$->\\{", "\\$\\{") : inlineExpression; } @Override public List splitAndEvaluate(final String inlineExpression) { - try (Context context = createContext()) { - List listProjection = createInlineExpressionParser(context).invokeMember("splitAndEvaluate", inlineExpression) - .as(new TypeLiteral>() { - }); - // org.graalvm.polyglot.Value#as only creates projections for classes in Truffle Context - return new ArrayList<>(listProjection); - } + return Strings.isNullOrEmpty(inlineExpression) ? Collections.emptyList() : flatten(evaluate(split(inlineExpression), CONTEXT)); } @Override public Closure evaluateClosure(final String inlineExpression) { - try (Context context = createContext()) { - return createInlineExpressionParser(context).invokeMember("evaluateClosure", inlineExpression).as(Closure.class); - } + throw new RuntimeException("GraalVM Truffle's Espresso implementation cannot return an instance of groovy.lang.Closure to the Host JVM."); } - private Value createInlineExpressionParser(final Context context) { - return context.getBindings("java").getMember(HotspotInlineExpressionParser.class.getName()).newInstance(); - } - - private Context createContext() { + private static Context createContext() { // TODO /~https://github.com/oracle/graal/issues/4555 not yet closed - ShardingSpherePreconditions.checkNotNull(JAVA_HOME, () -> new RuntimeException("Failed to determine the system's environment variable JAVA_HOME!")); return Context.newBuilder() .allowAllAccess(true) - .option("java.Properties.org.graalvm.home", JAVA_HOME) - .option("java.MultiThreaded", Boolean.TRUE.toString()) + .option("java.Properties.org.graalvm.home", System.getenv("JAVA_HOME")) .option("java.Classpath", JAVA_CLASSPATH) .build(); } + private List split(final String inlineExpression) { + List result = new ArrayList<>(); + StringBuilder segment = new StringBuilder(); + int bracketsDepth = 0; + for (int i = 0; i < inlineExpression.length(); i++) { + char each = inlineExpression.charAt(i); + switch (each) { + case SPLITTER: + if (bracketsDepth > 0) { + segment.append(each); + } else { + result.add(segment.toString().trim()); + segment.setLength(0); + } + break; + case '$': + if ('{' == inlineExpression.charAt(i + 1)) { + bracketsDepth++; + } + if ("->{".equals(inlineExpression.substring(i + 1, i + 4))) { + bracketsDepth++; + } + segment.append(each); + break; + case '}': + if (bracketsDepth > 0) { + bracketsDepth--; + } + segment.append(each); + break; + default: + segment.append(each); + break; + } + } + if (segment.length() > 0) { + result.add(segment.toString().trim()); + } + return result; + } + + private List evaluate(final List inlineExpressions, final Context context) { + List result = new ArrayList<>(inlineExpressions.size()); + for (String each : inlineExpressions) { + StringBuilder expression = new StringBuilder(handlePlaceHolder(each)); + if (!each.startsWith("\"")) { + expression.insert(0, '"'); + } + if (!each.endsWith("\"")) { + expression.append('"'); + } + result.add(evaluate(expression.toString(), context)); + } + return result; + } + + // TODO add cache + private Value evaluate(final String expression, final Context context) { + return context.getBindings("java") + .getMember(GroovyShell.class.getName()) + .newInstance() + .invokeMember("parse", expression) + .invokeMember("run"); + } + + private List flatten(final List segments) { + List result = new ArrayList<>(); + for (Value each : segments) { + if (!each.isString()) { + result.addAll(assemblyCartesianSegments(each)); + } else { + result.add(each.toString()); + } + } + return result; + } + + private List assemblyCartesianSegments(final Value segment) { + Set> cartesianValues = getCartesianValues(segment); + List result = new ArrayList<>(cartesianValues.size()); + for (List each : cartesianValues) { + result.add(assemblySegment(each, segment)); + } + return result; + } + + @SuppressWarnings("unchecked") + private Set> getCartesianValues(final Value segment) { + Object[] temp = segment.invokeMember("getValues").as(Object[].class); + List> result = new ArrayList<>(temp.length); + for (Object each : temp) { + if (null == each) { + continue; + } + if (each instanceof Collection) { + result.add(((Collection) each).stream().map(Object::toString).collect(Collectors.toCollection(LinkedHashSet::new))); + } else { + result.add(Sets.newHashSet(each.toString())); + } + } + return Sets.cartesianProduct(result); + } + + private String assemblySegment(final List cartesianValue, final Value segment) { + String[] temp = segment.invokeMember("getStrings").as(String[].class); + StringBuilder result = new StringBuilder(); + for (int i = 0; i < temp.length; i++) { + result.append(temp[i]); + if (i < cartesianValue.size()) { + result.append(cartesianValue.get(i)); + } + } + return result.toString(); + } + @Override public String getType() { return "ESPRESSO"; diff --git a/pom.xml b/pom.xml index d08a9caf277734..0bd3f2070f229d 100644 --- a/pom.xml +++ b/pom.xml @@ -127,7 +127,7 @@ 1.4.13 4.0.0 1.6.2 - 0.9.22 + 0.9.23 3.2.1 @@ -1185,7 +1185,7 @@ generateStandardMetadata - 22.3.1 + 23.0.1 true true true