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.encrypt.distsql.handler.update;
19  
20  import lombok.Setter;
21  import org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleAlterExecutor;
22  import org.apache.shardingsphere.distsql.handler.required.DistSQLExecutorCurrentRuleRequired;
23  import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
24  import org.apache.shardingsphere.encrypt.config.EncryptRuleConfiguration;
25  import org.apache.shardingsphere.encrypt.distsql.handler.converter.EncryptRuleStatementConverter;
26  import org.apache.shardingsphere.encrypt.distsql.segment.EncryptRuleSegment;
27  import org.apache.shardingsphere.encrypt.distsql.statement.AlterEncryptRuleStatement;
28  import org.apache.shardingsphere.encrypt.rule.EncryptRule;
29  import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
30  import org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
31  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
32  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.InvalidRuleConfigurationException;
33  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.MissingRequiredRuleException;
34  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
35  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
36  
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.HashMap;
40  import java.util.LinkedHashSet;
41  import java.util.Map;
42  import java.util.Objects;
43  import java.util.stream.Collectors;
44  
45  /**
46   * Alter encrypt rule executor.
47   */
48  @DistSQLExecutorCurrentRuleRequired(EncryptRule.class)
49  @Setter
50  public final class AlterEncryptRuleExecutor implements DatabaseRuleAlterExecutor<AlterEncryptRuleStatement, EncryptRule, EncryptRuleConfiguration> {
51      
52      private ShardingSphereDatabase database;
53      
54      private EncryptRule rule;
55      
56      @Override
57      public void checkBeforeUpdate(final AlterEncryptRuleStatement sqlStatement) {
58          checkToBeAlteredRules(sqlStatement);
59          checkColumnNames(sqlStatement);
60          checkToBeAlteredEncryptors(sqlStatement);
61      }
62      
63      private void checkToBeAlteredRules(final AlterEncryptRuleStatement sqlStatement) {
64          Collection<String> notExistEncryptTableNames = getToBeAlteredEncryptTableNames(sqlStatement).stream().filter(each -> !rule.getAllTableNames().contains(each)).collect(Collectors.toList());
65          ShardingSpherePreconditions.checkMustEmpty(notExistEncryptTableNames, () -> new MissingRequiredRuleException("Encrypt", database.getName(), notExistEncryptTableNames));
66      }
67      
68      private Collection<String> getToBeAlteredEncryptTableNames(final AlterEncryptRuleStatement sqlStatement) {
69          return sqlStatement.getRules().stream().map(EncryptRuleSegment::getTableName).collect(Collectors.toList());
70      }
71      
72      private void checkColumnNames(final AlterEncryptRuleStatement sqlStatement) {
73          for (EncryptRuleSegment each : sqlStatement.getRules()) {
74              ShardingSpherePreconditions.checkState(isColumnNameNotConflicts(each),
75                      () -> new InvalidRuleConfigurationException("encrypt", "assisted query column or like query column conflicts with logic column"));
76          }
77      }
78      
79      private boolean isColumnNameNotConflicts(final EncryptRuleSegment rule) {
80          return rule.getColumns().stream().noneMatch(each -> null != each.getLikeQuery() && each.getName().equals(each.getLikeQuery().getName())
81                  || null != each.getAssistedQuery() && each.getName().equals(each.getAssistedQuery().getName()));
82      }
83      
84      private void checkToBeAlteredEncryptors(final AlterEncryptRuleStatement sqlStatement) {
85          Collection<AlgorithmSegment> encryptors = new LinkedHashSet<>();
86          sqlStatement.getRules().forEach(each -> each.getColumns().forEach(column -> {
87              encryptors.add(column.getCipher().getEncryptor());
88              if (null != column.getAssistedQuery()) {
89                  encryptors.add(column.getAssistedQuery().getEncryptor());
90              }
91              if (null != column.getLikeQuery()) {
92                  encryptors.add(column.getLikeQuery().getEncryptor());
93              }
94          }));
95          encryptors.stream().filter(Objects::nonNull).forEach(each -> TypedSPILoader.checkService(EncryptAlgorithm.class, each.getName(), each.getProps()));
96      }
97      
98      @Override
99      public EncryptRuleConfiguration buildToBeAlteredRuleConfiguration(final AlterEncryptRuleStatement sqlStatement) {
100         return EncryptRuleStatementConverter.convert(sqlStatement.getRules());
101     }
102     
103     @Override
104     public EncryptRuleConfiguration buildToBeDroppedRuleConfiguration(final EncryptRuleConfiguration toBeAlteredRuleConfig) {
105         Collection<String> unusedEncryptor = UnusedAlgorithmFinder.findUnusedEncryptor(rule.getConfiguration());
106         Map<String, AlgorithmConfiguration> toBeDroppedEncryptors = new HashMap<>(unusedEncryptor.size(), 1F);
107         unusedEncryptor.forEach(each -> toBeDroppedEncryptors.put(each, rule.getConfiguration().getEncryptors().get(each)));
108         return new EncryptRuleConfiguration(Collections.emptyList(), toBeDroppedEncryptors);
109     }
110     
111     @Override
112     public Class<EncryptRule> getRuleClass() {
113         return EncryptRule.class;
114     }
115     
116     @Override
117     public Class<AlterEncryptRuleStatement> getType() {
118         return AlterEncryptRuleStatement.class;
119     }
120 }