1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.encrypt.distsql.handler.update;
19
20 import lombok.Setter;
21 import org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleCreateExecutor;
22 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
23 import org.apache.shardingsphere.encrypt.api.config.EncryptRuleConfiguration;
24 import org.apache.shardingsphere.encrypt.api.config.rule.EncryptTableRuleConfiguration;
25 import org.apache.shardingsphere.encrypt.distsql.handler.converter.EncryptRuleStatementConverter;
26 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptColumnItemSegment;
27 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptColumnSegment;
28 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptRuleSegment;
29 import org.apache.shardingsphere.encrypt.distsql.statement.CreateEncryptRuleStatement;
30 import org.apache.shardingsphere.encrypt.rule.EncryptRule;
31 import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
32 import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
33 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
34 import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.DuplicateRuleException;
35 import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.InvalidRuleConfigurationException;
36 import org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.EmptyStorageUnitException;
37 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
38 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
39
40 import java.util.Collection;
41 import java.util.LinkedHashSet;
42 import java.util.Objects;
43 import java.util.stream.Collectors;
44
45
46
47
48 @Setter
49 public final class CreateEncryptRuleExecutor implements DatabaseRuleCreateExecutor<CreateEncryptRuleStatement, EncryptRule, EncryptRuleConfiguration> {
50
51 private ShardingSphereDatabase database;
52
53 private EncryptRule rule;
54
55 @Override
56 public void checkBeforeUpdate(final CreateEncryptRuleStatement sqlStatement) {
57 if (!sqlStatement.isIfNotExists()) {
58 checkDuplicateRuleNames(sqlStatement);
59 }
60 checkColumnNames(sqlStatement);
61 checkAlgorithmTypes(sqlStatement);
62 checkToBeCreatedEncryptors(sqlStatement);
63 checkDataSources();
64 }
65
66 private void checkDuplicateRuleNames(final CreateEncryptRuleStatement sqlStatement) {
67 Collection<String> duplicatedRuleNames = getDuplicatedRuleNames(sqlStatement);
68 ShardingSpherePreconditions.checkMustEmpty(duplicatedRuleNames, () -> new DuplicateRuleException("encrypt", database.getName(), duplicatedRuleNames));
69 }
70
71 private Collection<String> getDuplicatedRuleNames(final CreateEncryptRuleStatement sqlStatement) {
72 Collection<String> currentRuleNames = new LinkedHashSet<>();
73 if (null != rule) {
74 currentRuleNames = rule.getConfiguration().getTables().stream().map(EncryptTableRuleConfiguration::getName).collect(Collectors.toSet());
75 }
76 return sqlStatement.getRules().stream().map(EncryptRuleSegment::getTableName).filter(currentRuleNames::contains).collect(Collectors.toSet());
77 }
78
79 private void checkColumnNames(final CreateEncryptRuleStatement sqlStatement) {
80 for (EncryptRuleSegment each : sqlStatement.getRules()) {
81 ShardingSpherePreconditions.checkState(isColumnNameNotConflicts(each),
82 () -> new InvalidRuleConfigurationException("encrypt", "assisted query column or like query column conflicts with logic column"));
83 }
84 }
85
86 private boolean isColumnNameNotConflicts(final EncryptRuleSegment rule) {
87 return rule.getColumns().stream().noneMatch(each -> null != each.getLikeQuery() && each.getName().equals(each.getLikeQuery().getName())
88 || null != each.getAssistedQuery() && each.getName().equals(each.getAssistedQuery().getName()));
89 }
90
91 private void checkAlgorithmTypes(final CreateEncryptRuleStatement sqlStatement) {
92 sqlStatement.getRules().stream().flatMap(each -> each.getColumns().stream()).forEach(each -> {
93 checkStandardAlgorithmType(each.getCipher());
94 checkLikeAlgorithmType(each.getLikeQuery());
95 checkAssistedAlgorithmType(each.getAssistedQuery());
96 });
97 }
98
99 private void checkStandardAlgorithmType(final EncryptColumnItemSegment itemSegment) {
100 if (null == itemSegment || null == itemSegment.getEncryptor()) {
101 return;
102 }
103 EncryptAlgorithm encryptAlgorithm = TypedSPILoader.getService(EncryptAlgorithm.class, itemSegment.getEncryptor().getName(), itemSegment.getEncryptor().getProps());
104 ShardingSpherePreconditions.checkState(encryptAlgorithm.getMetaData().isSupportDecrypt(), () -> new AlgorithmInitializationException(encryptAlgorithm, "Can not support decrypt"));
105 }
106
107 private void checkLikeAlgorithmType(final EncryptColumnItemSegment itemSegment) {
108 if (null == itemSegment || null == itemSegment.getEncryptor()) {
109 return;
110 }
111 EncryptAlgorithm encryptAlgorithm = TypedSPILoader.getService(EncryptAlgorithm.class, itemSegment.getEncryptor().getName(), itemSegment.getEncryptor().getProps());
112 ShardingSpherePreconditions.checkState(encryptAlgorithm.getMetaData().isSupportLike(), () -> new AlgorithmInitializationException(encryptAlgorithm, "Can not support like"));
113 }
114
115 private void checkAssistedAlgorithmType(final EncryptColumnItemSegment itemSegment) {
116 if (null == itemSegment || null == itemSegment.getEncryptor()) {
117 return;
118 }
119 EncryptAlgorithm encryptAlgorithm = TypedSPILoader.getService(EncryptAlgorithm.class, itemSegment.getEncryptor().getName(), itemSegment.getEncryptor().getProps());
120 ShardingSpherePreconditions.checkState(encryptAlgorithm.getMetaData().isSupportEquivalentFilter(),
121 () -> new AlgorithmInitializationException(encryptAlgorithm, "Can not support assist query"));
122 }
123
124 private void checkToBeCreatedEncryptors(final CreateEncryptRuleStatement sqlStatement) {
125 Collection<AlgorithmSegment> encryptors = new LinkedHashSet<>();
126 sqlStatement.getRules().forEach(each -> each.getColumns().forEach(column -> addToEncryptors(column, encryptors)));
127 encryptors.stream().filter(Objects::nonNull).forEach(each -> TypedSPILoader.checkService(EncryptAlgorithm.class, each.getName(), each.getProps()));
128 }
129
130 private void addToEncryptors(final EncryptColumnSegment column, final Collection<AlgorithmSegment> result) {
131 result.add(column.getCipher().getEncryptor());
132 if (null != column.getAssistedQuery()) {
133 result.add(column.getAssistedQuery().getEncryptor());
134 }
135 if (null != column.getLikeQuery()) {
136 result.add(column.getLikeQuery().getEncryptor());
137 }
138 }
139
140 private void checkDataSources() {
141 ShardingSpherePreconditions.checkNotEmpty(database.getResourceMetaData().getStorageUnits(), () -> new EmptyStorageUnitException(database.getName()));
142 }
143
144 @Override
145 public EncryptRuleConfiguration buildToBeCreatedRuleConfiguration(final CreateEncryptRuleStatement sqlStatement) {
146 Collection<EncryptRuleSegment> segments = sqlStatement.getRules();
147 if (sqlStatement.isIfNotExists()) {
148 Collection<String> duplicatedRuleNames = getDuplicatedRuleNames(sqlStatement);
149 segments.removeIf(each -> duplicatedRuleNames.contains(each.getTableName()));
150 }
151 return EncryptRuleStatementConverter.convert(segments);
152 }
153
154 @Override
155 public Class<EncryptRule> getRuleClass() {
156 return EncryptRule.class;
157 }
158
159 @Override
160 public Class<CreateEncryptRuleStatement> getType() {
161 return CreateEncryptRuleStatement.class;
162 }
163 }