1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.mask.rule;
19
20 import com.google.common.base.Preconditions;
21 import org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
22 import org.apache.shardingsphere.infra.rule.PartialRuleUpdateSupported;
23 import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
24 import org.apache.shardingsphere.infra.rule.scope.DatabaseRule;
25 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
26 import org.apache.shardingsphere.mask.api.config.MaskRuleConfiguration;
27 import org.apache.shardingsphere.mask.api.config.rule.MaskTableRuleConfiguration;
28 import org.apache.shardingsphere.mask.rule.attribute.MaskTableMapperRuleAttribute;
29 import org.apache.shardingsphere.mask.spi.MaskAlgorithm;
30
31 import java.util.Collection;
32 import java.util.HashSet;
33 import java.util.Map.Entry;
34 import java.util.Optional;
35 import java.util.concurrent.ConcurrentHashMap;
36 import java.util.concurrent.atomic.AtomicReference;
37 import java.util.stream.Collectors;
38
39
40
41
42 public final class MaskRule implements DatabaseRule, PartialRuleUpdateSupported<MaskRuleConfiguration> {
43
44 private final AtomicReference<MaskRuleConfiguration> configuration = new AtomicReference<>();
45
46 private final ConcurrentHashMap<String, MaskAlgorithm<?, ?>> maskAlgorithms;
47
48 private final ConcurrentHashMap<String, MaskTable> tables;
49
50 private final AtomicReference<RuleAttributes> attributes = new AtomicReference<>();
51
52 @SuppressWarnings("unchecked")
53 public MaskRule(final MaskRuleConfiguration ruleConfig) {
54 configuration.set(ruleConfig);
55 maskAlgorithms = ruleConfig.getMaskAlgorithms().entrySet().stream()
56 .collect(Collectors.toMap(Entry::getKey, entry -> TypedSPILoader.getService(MaskAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps()),
57 (oldValue, currentValue) -> oldValue, ConcurrentHashMap::new));
58 tables = ruleConfig.getTables().stream()
59 .collect(Collectors.toMap(each -> each.getName().toLowerCase(), each -> new MaskTable(each, maskAlgorithms), (oldValue, currentValue) -> oldValue, ConcurrentHashMap::new));
60 attributes.set(new RuleAttributes(new MaskTableMapperRuleAttribute(tables.keySet())));
61 }
62
63
64
65
66
67
68
69 public Optional<MaskTable> findMaskTable(final String tableName) {
70 return Optional.ofNullable(tables.get(tableName));
71 }
72
73 @Override
74 public RuleAttributes getAttributes() {
75 return attributes.get();
76 }
77
78 @Override
79 public MaskRuleConfiguration getConfiguration() {
80 return configuration.get();
81 }
82
83 @Override
84 public void updateConfiguration(final MaskRuleConfiguration toBeUpdatedRuleConfig) {
85 configuration.set(toBeUpdatedRuleConfig);
86 }
87
88 @Override
89 public boolean partialUpdate(final MaskRuleConfiguration toBeUpdatedRuleConfig) {
90 Collection<String> toBeAddedTableNames = toBeUpdatedRuleConfig.getTables().stream().map(MaskTableRuleConfiguration::getName).collect(Collectors.toList());
91 toBeAddedTableNames.removeAll(tables.keySet());
92 if (!toBeAddedTableNames.isEmpty()) {
93 toBeAddedTableNames.forEach(each -> addTableRule(each, toBeUpdatedRuleConfig));
94 attributes.set(new RuleAttributes(new MaskTableMapperRuleAttribute(tables.keySet())));
95 return true;
96 }
97 Collection<String> toBeRemovedTableNames = new HashSet<>(tables.keySet());
98 toBeRemovedTableNames.removeAll(toBeUpdatedRuleConfig.getTables().stream().map(MaskTableRuleConfiguration::getName).collect(Collectors.toList()));
99 if (!toBeRemovedTableNames.isEmpty()) {
100 toBeRemovedTableNames.stream().map(String::toLowerCase).forEach(tables::remove);
101 attributes.set(new RuleAttributes(new MaskTableMapperRuleAttribute(tables.keySet())));
102
103 return true;
104 }
105
106
107 return false;
108 }
109
110 private void addTableRule(final String tableName, final MaskRuleConfiguration toBeUpdatedRuleConfig) {
111 MaskTableRuleConfiguration tableRuleConfig = getTableRuleConfiguration(tableName, toBeUpdatedRuleConfig);
112 for (Entry<String, AlgorithmConfiguration> entry : toBeUpdatedRuleConfig.getMaskAlgorithms().entrySet()) {
113 maskAlgorithms.computeIfAbsent(entry.getKey(), key -> TypedSPILoader.getService(MaskAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps()));
114 }
115 tables.put(tableName.toLowerCase(), new MaskTable(tableRuleConfig, maskAlgorithms));
116 }
117
118 private MaskTableRuleConfiguration getTableRuleConfiguration(final String tableName, final MaskRuleConfiguration toBeUpdatedRuleConfig) {
119 Optional<MaskTableRuleConfiguration> result = toBeUpdatedRuleConfig.getTables().stream().filter(table -> table.getName().equals(tableName)).findFirst();
120 Preconditions.checkState(result.isPresent());
121 return result.get();
122 }
123 }