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.rule;
19  
20  import com.cedarsoftware.util.CaseInsensitiveMap;
21  import lombok.Getter;
22  import org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
23  import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
24  import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
25  import org.apache.shardingsphere.infra.rule.scope.DatabaseRule;
26  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
27  import org.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
28  import org.apache.shardingsphere.shadow.config.datasource.ShadowDataSourceConfiguration;
29  import org.apache.shardingsphere.shadow.config.table.ShadowTableConfiguration;
30  import org.apache.shardingsphere.shadow.constant.ShadowOrder;
31  import org.apache.shardingsphere.shadow.rule.attribute.ShadowDataSourceMapperRuleAttribute;
32  import org.apache.shardingsphere.shadow.spi.ShadowAlgorithm;
33  import org.apache.shardingsphere.shadow.spi.ShadowOperationType;
34  import org.apache.shardingsphere.shadow.spi.column.ColumnShadowAlgorithm;
35  import org.apache.shardingsphere.shadow.spi.hint.HintShadowAlgorithm;
36  
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.LinkedHashMap;
40  import java.util.LinkedList;
41  import java.util.Map;
42  import java.util.Map.Entry;
43  import java.util.Optional;
44  import java.util.stream.Collectors;
45  
46  /**
47   * Databases shadow rule.
48   */
49  public final class ShadowRule implements DatabaseRule {
50      
51      @Getter
52      private final ShadowRuleConfiguration configuration;
53      
54      private final Map<String, ShadowAlgorithm> shadowAlgorithms;
55      
56      private final ShadowAlgorithm defaultShadowAlgorithm;
57      
58      private final Map<String, ShadowDataSourceRule> dataSourceRules;
59      
60      private final Map<String, ShadowTableRule> tableRules;
61      
62      @Getter
63      private final RuleAttributes attributes;
64      
65      public ShadowRule(final ShadowRuleConfiguration ruleConfig) {
66          configuration = ruleConfig;
67          shadowAlgorithms = createShadowAlgorithms(ruleConfig.getShadowAlgorithms());
68          defaultShadowAlgorithm = shadowAlgorithms.get(ruleConfig.getDefaultShadowAlgorithmName());
69          dataSourceRules = createDataSourceRules(ruleConfig.getDataSources());
70          tableRules = createTableRules(ruleConfig.getTables());
71          attributes = new RuleAttributes(new ShadowDataSourceMapperRuleAttribute(dataSourceRules));
72      }
73      
74      private Map<String, ShadowAlgorithm> createShadowAlgorithms(final Map<String, AlgorithmConfiguration> shadowAlgorithmConfigs) {
75          return shadowAlgorithmConfigs.entrySet().stream().collect(Collectors.toMap(Entry::getKey,
76                  entry -> TypedSPILoader.getService(ShadowAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps()), (oldValue, currentValue) -> currentValue, LinkedHashMap::new));
77      }
78      
79      private Map<String, ShadowDataSourceRule> createDataSourceRules(final Collection<ShadowDataSourceConfiguration> dataSourceConfigs) {
80          return dataSourceConfigs.stream().collect(Collectors.toMap(ShadowDataSourceConfiguration::getName,
81                  each -> new ShadowDataSourceRule(each.getProductionDataSourceName(), each.getShadowDataSourceName()), (oldValue, currentValue) -> currentValue, CaseInsensitiveMap::new));
82      }
83      
84      private Map<String, ShadowTableRule> createTableRules(final Map<String, ShadowTableConfiguration> tableConfigs) {
85          return tableConfigs.entrySet().stream().collect(Collectors.toMap(Entry::getKey,
86                  entry -> new ShadowTableRule(entry.getKey(), entry.getValue().getDataSourceNames(), entry.getValue().getShadowAlgorithmNames(), shadowAlgorithms),
87                  (oldValue, currentValue) -> currentValue, CaseInsensitiveMap::new));
88      }
89      
90      /**
91       * Whether contains shadow algorithm.
92       *
93       * @param algorithmName algorithm name
94       * @return contains shadow algorithm or not
95       */
96      public boolean containsShadowAlgorithm(final String algorithmName) {
97          return shadowAlgorithms.containsKey(algorithmName);
98      }
99      
100     /**
101      * Get default shadow algorithm.
102      *
103      * @return shadow algorithm
104      */
105     @HighFrequencyInvocation
106     public Optional<ShadowAlgorithm> getDefaultShadowAlgorithm() {
107         return Optional.ofNullable(defaultShadowAlgorithm);
108     }
109     
110     /**
111      * Filter shadow tables.
112      *
113      * @param tableNames to be filtered table names
114      * @return filtered shadow tables
115      */
116     @HighFrequencyInvocation
117     public Collection<String> filterShadowTables(final Collection<String> tableNames) {
118         Collection<String> result = new LinkedList<>();
119         for (String each : tableNames) {
120             if (tableRules.containsKey(each)) {
121                 result.add(each);
122             }
123         }
124         return result;
125     }
126     
127     /**
128      * Get all shadow table names.
129      *
130      * @return shadow table names
131      */
132     @HighFrequencyInvocation
133     public Collection<String> getAllShadowTableNames() {
134         return tableRules.keySet();
135     }
136     
137     /**
138      * Get all hint shadow algorithms.
139      *
140      * @return all hint shadow algorithms
141      */
142     @HighFrequencyInvocation
143     @SuppressWarnings("unchecked")
144     public Collection<HintShadowAlgorithm<Comparable<?>>> getAllHintShadowAlgorithms() {
145         Collection<HintShadowAlgorithm<Comparable<?>>> result = new LinkedList<>();
146         for (Entry<String, ShadowAlgorithm> entry : shadowAlgorithms.entrySet()) {
147             if (entry.getValue() instanceof HintShadowAlgorithm) {
148                 result.add((HintShadowAlgorithm<Comparable<?>>) entry.getValue());
149             }
150         }
151         return result;
152     }
153     
154     /**
155      * Get hint shadow algorithms.
156      *
157      * @param tableName table name
158      * @return hint shadow algorithms
159      */
160     @HighFrequencyInvocation
161     @SuppressWarnings("unchecked")
162     public Collection<HintShadowAlgorithm<Comparable<?>>> getHintShadowAlgorithms(final String tableName) {
163         Collection<HintShadowAlgorithm<Comparable<?>>> result = new LinkedList<>();
164         for (String each : tableRules.get(tableName).getHintShadowAlgorithmNames()) {
165             result.add((HintShadowAlgorithm<Comparable<?>>) shadowAlgorithms.get(each));
166         }
167         return result;
168     }
169     
170     /**
171      * Get column shadow algorithms.
172      *
173      * @param operationType shadow operation type
174      * @param tableName table name
175      * @param shadowColumnName shadow column name
176      * @return column shadow algorithms
177      */
178     @HighFrequencyInvocation
179     @SuppressWarnings("unchecked")
180     public Collection<ColumnShadowAlgorithm<Comparable<?>>> getColumnShadowAlgorithms(final ShadowOperationType operationType, final String tableName, final String shadowColumnName) {
181         Collection<ColumnShadowAlgorithm<Comparable<?>>> result = new LinkedList<>();
182         for (ShadowAlgorithmNameRule each : tableRules.get(tableName).getColumnShadowAlgorithmNames().getOrDefault(operationType, Collections.emptyList())) {
183             if (shadowColumnName.equals(each.getShadowColumnName())) {
184                 result.add((ColumnShadowAlgorithm<Comparable<?>>) shadowAlgorithms.get(each.getShadowAlgorithmName()));
185             }
186         }
187         return result;
188     }
189     
190     /**
191      * Get shadow column names.
192      *
193      * @param operationType shadow operation type
194      * @param tableName table name
195      * @return got shadow column names
196      */
197     @HighFrequencyInvocation
198     public Collection<String> getShadowColumnNames(final ShadowOperationType operationType, final String tableName) {
199         Collection<String> result = new LinkedList<>();
200         for (ShadowAlgorithmNameRule each : tableRules.get(tableName).getColumnShadowAlgorithmNames().getOrDefault(operationType, Collections.emptyList())) {
201             result.add(each.getShadowColumnName());
202         }
203         return result;
204     }
205     
206     /**
207      * Get shadow data source mappings.
208      *
209      * @param tableName table name
210      * @return shadow data source mappings
211      */
212     @HighFrequencyInvocation
213     public Map<String, String> getShadowDataSourceMappings(final String tableName) {
214         Map<String, String> result = new LinkedHashMap<>(dataSourceRules.size(), 1F);
215         for (String each : tableRules.get(tableName).getLogicDataSourceNames()) {
216             ShadowDataSourceRule dataSourceRule = dataSourceRules.get(each);
217             result.put(dataSourceRule.getProductionDataSource(), dataSourceRule.getShadowDataSource());
218         }
219         return result;
220     }
221     
222     /**
223      * Get all shadow data source mappings.
224      *
225      * @return all shadow data source mappings
226      */
227     @HighFrequencyInvocation
228     public Map<String, String> getAllShadowDataSourceMappings() {
229         Map<String, String> result = new LinkedHashMap<>(dataSourceRules.size(), 1F);
230         for (Entry<String, ShadowDataSourceRule> entry : dataSourceRules.entrySet()) {
231             ShadowDataSourceRule dataSourceRule = entry.getValue();
232             result.put(dataSourceRule.getProductionDataSource(), dataSourceRule.getShadowDataSource());
233         }
234         return result;
235     }
236     
237     /**
238      * Find production data source name.
239      *
240      * @param logicDataSourceName logic data source name
241      * @return found production data source name
242      */
243     @HighFrequencyInvocation
244     public Optional<String> findProductionDataSourceName(final String logicDataSourceName) {
245         ShadowDataSourceRule dataSourceRule = dataSourceRules.get(logicDataSourceName);
246         return null == dataSourceRule ? Optional.empty() : Optional.of(dataSourceRule.getProductionDataSource());
247     }
248     
249     @Override
250     public int getOrder() {
251         return ShadowOrder.ORDER;
252     }
253 }