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.shadow.route.engine.impl;
19  
20  import lombok.RequiredArgsConstructor;
21  import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
22  import org.apache.shardingsphere.infra.route.context.RouteContext;
23  import org.apache.shardingsphere.shadow.api.shadow.ShadowOperationType;
24  import org.apache.shardingsphere.shadow.api.shadow.hint.HintShadowAlgorithm;
25  import org.apache.shardingsphere.shadow.condition.ShadowDetermineCondition;
26  import org.apache.shardingsphere.shadow.route.engine.ShadowRouteEngine;
27  import org.apache.shardingsphere.shadow.route.engine.determiner.HintShadowAlgorithmDeterminer;
28  import org.apache.shardingsphere.shadow.rule.ShadowRule;
29  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.CommentSegment;
30  import org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
31  
32  import java.util.Collection;
33  import java.util.Collections;
34  import java.util.Map;
35  import java.util.Optional;
36  import java.util.stream.Collectors;
37  
38  /**
39   * Shadow non-DML statement routing engine.
40   */
41  @RequiredArgsConstructor
42  public final class ShadowNonDMLStatementRoutingEngine implements ShadowRouteEngine {
43      
44      private final SQLStatementContext sqlStatementContext;
45      
46      @Override
47      public void route(final RouteContext routeContext, final ShadowRule rule) {
48          decorateRouteContext(routeContext, rule, findShadowDataSourceMappings(rule));
49      }
50      
51      private Map<String, String> findShadowDataSourceMappings(final ShadowRule rule) {
52          Optional<Collection<String>> sqlComments = parseSQLComments();
53          if (!sqlComments.isPresent()) {
54              return Collections.emptyMap();
55          }
56          if (isMatchAnyNoteShadowAlgorithms(rule, createShadowDetermineCondition(sqlComments.get()))) {
57              return rule.getAllShadowDataSourceMappings();
58          }
59          return Collections.emptyMap();
60      }
61      
62      private Optional<Collection<String>> parseSQLComments() {
63          // TODO use SQLHintUtil to parse SQL comments and remove hint in sql
64          Collection<String> result = ((AbstractSQLStatement) sqlStatementContext.getSqlStatement()).getCommentSegments().stream().map(CommentSegment::getText).collect(Collectors.toList());
65          return result.isEmpty() ? Optional.empty() : Optional.of(result);
66      }
67      
68      private ShadowDetermineCondition createShadowDetermineCondition(final Collection<String> sqlComments) {
69          return new ShadowDetermineCondition("", ShadowOperationType.HINT_MATCH).initSQLComments(sqlComments);
70      }
71      
72      private boolean isMatchAnyNoteShadowAlgorithms(final ShadowRule rule, final ShadowDetermineCondition shadowCondition) {
73          for (HintShadowAlgorithm<Comparable<?>> each : rule.getAllHintShadowAlgorithms()) {
74              if (HintShadowAlgorithmDeterminer.isShadow(each, shadowCondition, rule)) {
75                  return true;
76              }
77          }
78          return false;
79      }
80  }