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