View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.infra.expr.espresso;
19  
20  import lombok.SneakyThrows;
21  
22  /**
23   * Reflect Context.
24   * Avoid using JDK21 bytecode during compilation. Refer to `org.graalvm.polyglot.Context`.
25   */
26  public final class ReflectContext implements AutoCloseable {
27      
28      private static final String CONTEXT_CLASS_NAME = "org.graalvm.polyglot.Context";
29      
30      private final Object contextInstance;
31      
32      /**
33       * This method is a simulation of the following operation.
34       * // CHECKSTYLE:OFF
35       * <pre class="code">
36       * private final Context context = Context.newBuilder("java")
37       *             .allowAllAccess(true)
38       *             .allowValueSharing(false)
39       *             .option("java.Classpath", JAVA_CLASSPATH)
40       *             .build();
41       * </pre>
42       * // CHECKSTYLE:ON
43       * TODO <a href="https://github.com/oracle/graal/issues/4555">oracle/graal#4555</a> not yet closed.
44       * Maybe sometimes shardingsphere need `.option("java.Properties.org.graalvm.home", System.getenv("JAVA_HOME")).
45       *
46       * @param javaClassPath java class path
47       */
48      @SneakyThrows
49      public ReflectContext(final String javaClassPath) {
50          Object builderInstance = Class.forName(CONTEXT_CLASS_NAME)
51                  .getMethod("newBuilder", String[].class)
52                  .invoke(null, (Object) new String[]{"java"});
53          builderInstance = builderInstance.getClass()
54                  .getMethod("allowAllAccess", boolean.class)
55                  .invoke(builderInstance, true);
56          builderInstance = builderInstance.getClass()
57                  .getMethod("allowValueSharing", boolean.class)
58                  .invoke(builderInstance, false);
59          builderInstance = builderInstance.getClass()
60                  .getMethod("option", String.class, String.class)
61                  .invoke(builderInstance, "java.Classpath", javaClassPath);
62          contextInstance = builderInstance.getClass()
63                  .getMethod("build")
64                  .invoke(builderInstance);
65      }
66      
67      /**
68       * Returns a value that represents the top-most bindings of a language.
69       *
70       * @param languageId languageId
71       * @return {@link org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
72       */
73      @SneakyThrows
74      public ReflectValue getBindings(final String languageId) {
75          Object valueInstance = Class.forName(CONTEXT_CLASS_NAME)
76                  .getMethod("getBindings", String.class)
77                  .invoke(contextInstance, languageId);
78          return new ReflectValue(valueInstance);
79      }
80      
81      @Override
82      @SneakyThrows
83      public void close() {
84          Class.forName(CONTEXT_CLASS_NAME).getMethod("close").invoke(contextInstance);
85      }
86  }