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       * <pre class="code">
35       * private final Context context = Context.newBuilder("java")
36       *             .allowAllAccess(true)
37       *             .allowValueSharing(false)
38       *             .option("java.Classpath", JAVA_CLASSPATH)
39       *             .build();
40       * </pre>
41       * TODO <a href="https://github.com/oracle/graal/issues/4555">oracle/graal#4555</a> not yet closed.
42       * Maybe sometimes shardingsphere need `.option("java.Properties.org.graalvm.home", System.getenv("JAVA_HOME")).
43       *
44       * @param javaClassPath java class path
45       */
46      @SneakyThrows
47      public ReflectContext(final String javaClassPath) {
48          Object builderInstance = Class.forName(CONTEXT_CLASS_NAME)
49                  .getMethod("newBuilder", String[].class)
50                  .invoke(null, (Object) new String[]{"java"});
51          builderInstance = builderInstance.getClass()
52                  .getMethod("allowAllAccess", boolean.class)
53                  .invoke(builderInstance, true);
54          builderInstance = builderInstance.getClass()
55                  .getMethod("allowValueSharing", boolean.class)
56                  .invoke(builderInstance, false);
57          builderInstance = builderInstance.getClass()
58                  .getMethod("option", String.class, String.class)
59                  .invoke(builderInstance, "java.Classpath", javaClassPath);
60          contextInstance = builderInstance.getClass()
61                  .getMethod("build")
62                  .invoke(builderInstance);
63      }
64      
65      /**
66       * Returns a value that represents the top-most bindings of a language.
67       *
68       * @param languageId languageId
69       * @return {@link org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
70       */
71      @SneakyThrows
72      public ReflectValue getBindings(final String languageId) {
73          Object valueInstance = Class.forName(CONTEXT_CLASS_NAME)
74                  .getMethod("getBindings", String.class)
75                  .invoke(contextInstance, languageId);
76          return new ReflectValue(valueInstance);
77      }
78      
79      @Override
80      @SneakyThrows
81      public void close() {
82          Class.forName(CONTEXT_CLASS_NAME).getMethod("close").invoke(contextInstance);
83      }
84  }