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.route.engine.impl;
19  
20  import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
21  import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
22  import org.apache.shardingsphere.infra.hint.HintManager;
23  import org.apache.shardingsphere.infra.hint.HintValueContext;
24  import org.apache.shardingsphere.infra.exception.kernel.syntax.hint.DataSourceHintNotExistsException;
25  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
26  import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
27  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
28  import org.apache.shardingsphere.infra.route.SQLRouter;
29  import org.apache.shardingsphere.infra.route.context.RouteContext;
30  import org.apache.shardingsphere.infra.route.context.RouteMapper;
31  import org.apache.shardingsphere.infra.route.context.RouteUnit;
32  import org.apache.shardingsphere.infra.route.engine.SQLRouteExecutor;
33  import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
34  import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
35  import org.apache.shardingsphere.infra.session.query.QueryContext;
36  import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader;
37  
38  import java.util.Collection;
39  import java.util.Collections;
40  import java.util.Map;
41  import java.util.Map.Entry;
42  import java.util.Optional;
43  
44  /**
45   * Partial SQL route executor.
46   */
47  @HighFrequencyInvocation
48  public final class PartialSQLRouteExecutor implements SQLRouteExecutor {
49      
50      private final ConfigurationProperties props;
51      
52      @SuppressWarnings("rawtypes")
53      private final Map<ShardingSphereRule, SQLRouter> routers;
54      
55      public PartialSQLRouteExecutor(final Collection<ShardingSphereRule> rules, final ConfigurationProperties props) {
56          this.props = props;
57          routers = OrderedSPILoader.getServices(SQLRouter.class, rules);
58      }
59      
60      @Override
61      @SuppressWarnings({"unchecked", "rawtypes"})
62      public RouteContext route(final ConnectionContext connectionContext, final QueryContext queryContext, final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database) {
63          RouteContext result = new RouteContext();
64          Optional<String> dataSourceName = findDataSourceByHint(queryContext.getHintValueContext(), database.getResourceMetaData().getStorageUnits());
65          if (dataSourceName.isPresent()) {
66              result.getRouteUnits().add(new RouteUnit(new RouteMapper(dataSourceName.get(), dataSourceName.get()), Collections.emptyList()));
67              return result;
68          }
69          for (Entry<ShardingSphereRule, SQLRouter> entry : routers.entrySet()) {
70              if (result.getRouteUnits().isEmpty()) {
71                  result = entry.getValue().createRouteContext(queryContext, globalRuleMetaData, database, entry.getKey(), props, connectionContext);
72              } else {
73                  entry.getValue().decorateRouteContext(result, queryContext, database, entry.getKey(), props, connectionContext);
74              }
75          }
76          if (result.getRouteUnits().isEmpty() && 1 == database.getResourceMetaData().getStorageUnits().size()) {
77              String singleDataSourceName = database.getResourceMetaData().getStorageUnits().keySet().iterator().next();
78              result.getRouteUnits().add(new RouteUnit(new RouteMapper(singleDataSourceName, singleDataSourceName), Collections.emptyList()));
79          }
80          return result;
81      }
82      
83      private Optional<String> findDataSourceByHint(final HintValueContext hintValueContext, final Map<String, StorageUnit> storageUnits) {
84          Optional<String> result = HintManager.isInstantiated() && HintManager.getDataSourceName().isPresent() ? HintManager.getDataSourceName() : hintValueContext.findHintDataSourceName();
85          if (result.isPresent() && !storageUnits.containsKey(result.get())) {
86              throw new DataSourceHintNotExistsException(result.get());
87          }
88          return result;
89      }
90  }