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.config.EncryptRuleConfiguration;
24 import org.apache.shardingsphere.encrypt.distsql.handler.converter.EncryptRuleStatementConverter;
25 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptColumnItemSegment;
26 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptColumnSegment;
27 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptRuleSegment;
28 import org.apache.shardingsphere.encrypt.distsql.statement.CreateEncryptRuleStatement;
29 import org.apache.shardingsphere.encrypt.rule.EncryptRule;
30 import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
31 import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
32 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
33 import org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.EmptyStorageUnitException;
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.metadata.database.ShardingSphereDatabase;
37 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
38
39 import java.util.Collection;
40 import java.util.Collections;
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 return null == rule ? Collections.emptyList() : sqlStatement.getRules().stream().map(EncryptRuleSegment::getTableName).filter(rule.getAllTableNames()::contains).collect(Collectors.toSet());
73 }
74
75 private void checkColumnNames(final CreateEncryptRuleStatement sqlStatement) {
76 for (EncryptRuleSegment each : sqlStatement.getRules()) {
77 ShardingSpherePreconditions.checkState(isColumnNameNotConflicts(each),
78 () -> new InvalidRuleConfigurationException("encrypt", "assisted query column or like query column conflicts with logic column"));
79 }
80 }
81
82 private boolean isColumnNameNotConflicts(final EncryptRuleSegment rule) {
83 return rule.getColumns().stream().noneMatch(each -> null != each.getLikeQuery() && each.getName().equals(each.getLikeQuery().getName())
84 || null != each.getAssistedQuery() && each.getName().equals(each.getAssistedQuery().getName()));
85 }
86
87 private void checkAlgorithmTypes(final CreateEncryptRuleStatement sqlStatement) {
88 sqlStatement.getRules().stream().flatMap(each -> each.getColumns().stream()).forEach(each -> {
89 checkStandardAlgorithmType(each.getCipher());
90 checkLikeAlgorithmType(each.getLikeQuery());
91 checkAssistedAlgorithmType(each.getAssistedQuery());
92 });
93 }
94
95 private void checkStandardAlgorithmType(final EncryptColumnItemSegment itemSegment) {
96 if (null == itemSegment || null == itemSegment.getEncryptor()) {
97 return;
98 }
99 EncryptAlgorithm encryptAlgorithm = TypedSPILoader.getService(EncryptAlgorithm.class, itemSegment.getEncryptor().getName(), itemSegment.getEncryptor().getProps());
100 ShardingSpherePreconditions.checkState(encryptAlgorithm.getMetaData().isSupportDecrypt(), () -> new AlgorithmInitializationException(encryptAlgorithm, "Can not support decrypt"));
101 }
102
103 private void checkLikeAlgorithmType(final EncryptColumnItemSegment itemSegment) {
104 if (null == itemSegment || null == itemSegment.getEncryptor()) {
105 return;
106 }
107 EncryptAlgorithm encryptAlgorithm = TypedSPILoader.getService(EncryptAlgorithm.class, itemSegment.getEncryptor().getName(), itemSegment.getEncryptor().getProps());
108 ShardingSpherePreconditions.checkState(encryptAlgorithm.getMetaData().isSupportLike(), () -> new AlgorithmInitializationException(encryptAlgorithm, "Can not support like"));
109 }
110
111 private void checkAssistedAlgorithmType(final EncryptColumnItemSegment itemSegment) {
112 if (null == itemSegment || null == itemSegment.getEncryptor()) {
113 return;
114 }
115 EncryptAlgorithm encryptAlgorithm = TypedSPILoader.getService(EncryptAlgorithm.class, itemSegment.getEncryptor().getName(), itemSegment.getEncryptor().getProps());
116 ShardingSpherePreconditions.checkState(encryptAlgorithm.getMetaData().isSupportEquivalentFilter(),
117 () -> new AlgorithmInitializationException(encryptAlgorithm, "Can not support assist query"));
118 }
119
120 private void checkToBeCreatedEncryptors(final CreateEncryptRuleStatement sqlStatement) {
121 Collection<AlgorithmSegment> encryptors = new LinkedHashSet<>();
122 sqlStatement.getRules().forEach(each -> each.getColumns().forEach(column -> addToEncryptors(column, encryptors)));
123 encryptors.stream().filter(Objects::nonNull).forEach(each -> TypedSPILoader.checkService(EncryptAlgorithm.class, each.getName(), each.getProps()));
124 }
125
126 private void addToEncryptors(final EncryptColumnSegment column, final Collection<AlgorithmSegment> result) {
127 result.add(column.getCipher().getEncryptor());
128 if (null != column.getAssistedQuery()) {
129 result.add(column.getAssistedQuery().getEncryptor());
130 }
131 if (null != column.getLikeQuery()) {
132 result.add(column.getLikeQuery().getEncryptor());
133 }
134 }
135
136 private void checkDataSources() {
137 ShardingSpherePreconditions.checkNotEmpty(database.getResourceMetaData().getStorageUnits(), () -> new EmptyStorageUnitException(database.getName()));
138 }
139
140 @Override
141 public EncryptRuleConfiguration buildToBeCreatedRuleConfiguration(final CreateEncryptRuleStatement sqlStatement) {
142 Collection<EncryptRuleSegment> segments = sqlStatement.getRules();
143 if (sqlStatement.isIfNotExists()) {
144 Collection<String> duplicatedRuleNames = getDuplicatedRuleNames(sqlStatement);
145 segments.removeIf(each -> duplicatedRuleNames.contains(each.getTableName()));
146 }
147 return EncryptRuleStatementConverter.convert(segments);
148 }
149
150 @Override
151 public Class<EncryptRule> getRuleClass() {
152 return EncryptRule.class;
153 }
154
155 @Override
156 public Class<CreateEncryptRuleStatement> getType() {
157 return CreateEncryptRuleStatement.class;
158 }
159 }