Skip to content

Commit

Permalink
Prevent ReadwriteSplitting rule class from parsing Groovy syntax unde…
Browse files Browse the repository at this point in the history
…r GraalVM Native Image
  • Loading branch information
linghengqian committed Nov 12, 2023
1 parent d4379eb commit a7d5f31
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.shardingsphere.infra.rule.identifier.type.DataSourceContainedRule;
import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.infra.util.groovy.GroovyUtils;
import org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.WeightReadQueryLoadBalanceAlgorithm;
import org.apache.shardingsphere.readwritesplitting.api.ReadwriteSplittingRuleConfiguration;
import org.apache.shardingsphere.readwritesplitting.api.rule.ReadwriteSplittingDataSourceRuleConfiguration;
Expand All @@ -49,6 +50,8 @@
*/
public final class ReadwriteSplittingRuleConfigurationChecker implements RuleConfigurationChecker<ReadwriteSplittingRuleConfiguration> {

private final String inlineExpressionTypePrefix = "<LITERAL>";

@Override
public void check(final String databaseName, final ReadwriteSplittingRuleConfiguration config, final Map<String, DataSource> dataSourceMap, final Collection<ShardingSphereRule> builtRules) {
Collection<ReadwriteSplittingDataSourceRuleConfiguration> configs = config.getDataSources();
Expand Down Expand Up @@ -79,7 +82,10 @@ private void checkDataSources(final String databaseName, final Map<String, DataS

private void checkWriteDataSourceNames(final String databaseName, final Map<String, DataSource> dataSourceMap, final Collection<String> addedWriteDataSourceNames,
final ReadwriteSplittingDataSourceRuleConfiguration config, final Collection<ShardingSphereRule> rules) {
for (String each : InlineExpressionParserFactory.newInstance(config.getWriteDataSourceName()).splitAndEvaluate()) {
String resultInlineExpression = GroovyUtils.isNotRuntimeInGraalVMNativeImage()
? config.getWriteDataSourceName()
: inlineExpressionTypePrefix + config.getWriteDataSourceName();
for (String each : InlineExpressionParserFactory.newInstance(resultInlineExpression).splitAndEvaluate()) {
ShardingSpherePreconditions.checkState(dataSourceMap.containsKey(each) || containsInOtherRules(each, rules),
() -> new DataSourceNameExistedException(String.format("Write data source name `%s` not in database `%s`.", each, databaseName)));
ShardingSpherePreconditions.checkState(addedWriteDataSourceNames.add(each),
Expand All @@ -97,7 +103,10 @@ private boolean containsInOtherRules(final String datasourceName, final Collecti
}

private void checkReadeDataSourceNames(final String databaseName, final Map<String, DataSource> dataSourceMap, final Collection<String> addedReadDataSourceNames, final String readDataSourceName) {
for (String each : InlineExpressionParserFactory.newInstance(readDataSourceName).splitAndEvaluate()) {
String resultInlineExpression = GroovyUtils.isNotRuntimeInGraalVMNativeImage()
? readDataSourceName
: inlineExpressionTypePrefix + readDataSourceName;
for (String each : InlineExpressionParserFactory.newInstance(resultInlineExpression).splitAndEvaluate()) {
ShardingSpherePreconditions.checkState(dataSourceMap.containsKey(each),
() -> new DataSourceNameExistedException(String.format("Read data source name `%s` not in database `%s`.", each, databaseName)));
ShardingSpherePreconditions.checkState(addedReadDataSourceNames.add(each),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.expr.core.InlineExpressionParserFactory;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.infra.util.groovy.GroovyUtils;
import org.apache.shardingsphere.mode.event.storage.StorageNodeDataSourceChangedEvent;
import org.apache.shardingsphere.mode.event.storage.StorageNodeDataSourceDeletedEvent;
import org.apache.shardingsphere.readwritesplitting.api.ReadwriteSplittingRuleConfiguration;
Expand All @@ -57,6 +58,8 @@
*/
public final class ReadwriteSplittingRule implements DatabaseRule, DataSourceContainedRule, StaticDataSourceContainedRule, ExportableRule, StorageConnectorReusableRule {

private final String inlineExpressionTypePrefix = "<LITERAL>";

private final String databaseName;

@Getter
Expand Down Expand Up @@ -103,10 +106,19 @@ private Map<String, ReadwriteSplittingDataSourceRule> createDataSourceRules(fina

private Map<String, ReadwriteSplittingDataSourceRule> createStaticDataSourceRules(final ReadwriteSplittingDataSourceRuleConfiguration config,
final ReadQueryLoadBalanceAlgorithm loadBalanceAlgorithm) {
List<String> inlineReadwriteDataSourceNames = InlineExpressionParserFactory.newInstance(config.getName()).splitAndEvaluate();
List<String> inlineWriteDatasourceNames = InlineExpressionParserFactory.newInstance(config.getWriteDataSourceName()).splitAndEvaluate();
String resultConfigNameInlineExpression = GroovyUtils.isNotRuntimeInGraalVMNativeImage()
? config.getName()
: inlineExpressionTypePrefix + config.getName();
List<String> inlineReadwriteDataSourceNames = InlineExpressionParserFactory.newInstance(resultConfigNameInlineExpression).splitAndEvaluate();
String resultConfigWriteDataSourceNameInlineExpression = GroovyUtils.isNotRuntimeInGraalVMNativeImage()
? config.getWriteDataSourceName()
: inlineExpressionTypePrefix + config.getWriteDataSourceName();
List<String> inlineWriteDatasourceNames = InlineExpressionParserFactory.newInstance(resultConfigWriteDataSourceNameInlineExpression).splitAndEvaluate();
List<List<String>> inlineReadDatasourceNames = config.getReadDataSourceNames().stream()
.map(each -> InlineExpressionParserFactory.newInstance(each).splitAndEvaluate()).collect(Collectors.toList());
.map(each -> {
String resultInlineExpression = GroovyUtils.isNotRuntimeInGraalVMNativeImage() ? each : inlineExpressionTypePrefix + each;
return InlineExpressionParserFactory.newInstance(resultInlineExpression).splitAndEvaluate();
}).collect(Collectors.toList());
ShardingSpherePreconditions.checkState(inlineWriteDatasourceNames.size() == inlineReadwriteDataSourceNames.size(),
() -> new InvalidInlineExpressionDataSourceNameException("Inline expression write data source names size error."));
inlineReadDatasourceNames.forEach(each -> ShardingSpherePreconditions.checkState(each.size() == inlineReadwriteDataSourceNames.size(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@
* - `org.apache.shardingsphere.infra.expr.groovy.GroovyInlineExpressionParser`
*/
public class GroovyUtils {

/**
* If the context class is in the GraalVM Native Image Runtime, this function returns `false`.
* This function returns `true` when the context class is in GraalVM Native Image BuildTime or under Hotspot JVM.
* <p/>
* ShardingSphere use the System Property of `org.graalvm.nativeimage.imagecode` to identify whether this class is
* in the GraalVM Native Image environment. The background of this property comes from
* <a href="https://junit.org/junit5/docs/5.10.0/api/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledInNativeImage.html">Annotation Interface DisabledInNativeImage</a>.
*
* @return The judgment result of the environment where the context class is located
*/
public static Boolean isNotRuntimeInGraalVMNativeImage() {
return null == System.getProperty("org.graalvm.nativeimage.imagecode") || !"runtime".equals(System.getProperty("org.graalvm.nativeimage.imagecode"));
}

/**
* Split GroovyShell expression to a ArrayList.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import org.apache.shardingsphere.infra.util.groovy.GroovyUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
Expand Down Expand Up @@ -87,10 +88,6 @@ public static JDBCRepositorySQL load(final String type) {
* `com.oracle.svm.core.jdk.resources.NativeImageResourceFileSystem` does not autoload. This is mainly to align the
* behavior of `ZipFileSystemProvider`, so ShardingSphere need to manually open and close the FileSystem
* corresponding to the `resource:/` scheme. For more background reference <a href="https://github.com/oracle/graal/issues/7682">oracle/graal#7682</a>.
* <p/>
* ShardingSphere use the System Property of `org.graalvm.nativeimage.imagecode` to identify whether this class is in the
* GraalVM Native Image environment. The background of this property comes from
* <a href="https://junit.org/junit5/docs/5.10.0/api/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledInNativeImage.html">Annotation Interface DisabledInNativeImage</a>.
*
* @param url url
* @param type type of JDBC repository SQL
Expand All @@ -101,7 +98,7 @@ public static JDBCRepositorySQL load(final String type) {
* @see sun.nio.fs.UnixFileSystemProvider
*/
private static JDBCRepositorySQL loadFromDirectory(final URL url, final String type) throws URISyntaxException, IOException {
if (null == System.getProperty("org.graalvm.nativeimage.imagecode") || !"runtime".equals(System.getProperty("org.graalvm.nativeimage.imagecode"))) {
if (GroovyUtils.isNotRuntimeInGraalVMNativeImage()) {
return loadFromDirectoryLegacy(url, type);
} else {
try (FileSystem ignored = FileSystems.newFileSystem(URI.create("resource:/"), Collections.emptyMap())) {
Expand Down

0 comments on commit a7d5f31

Please sign in to comment.