1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
92
93
94
95
96 public boolean containsShadowAlgorithm(final String algorithmName) {
97 return shadowAlgorithms.containsKey(algorithmName);
98 }
99
100
101
102
103
104
105 @HighFrequencyInvocation
106 public Optional<ShadowAlgorithm> getDefaultShadowAlgorithm() {
107 return Optional.ofNullable(defaultShadowAlgorithm);
108 }
109
110
111
112
113
114
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
129
130
131
132 @HighFrequencyInvocation
133 public Collection<String> getAllShadowTableNames() {
134 return tableRules.keySet();
135 }
136
137
138
139
140
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
156
157
158
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
172
173
174
175
176
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
192
193
194
195
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
208
209
210
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
224
225
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
239
240
241
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 }