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.mask.rule;
19  
20  import com.cedarsoftware.util.CaseInsensitiveMap;
21  import com.cedarsoftware.util.CaseInsensitiveSet;
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.config.MaskRuleConfiguration;
27  import org.apache.shardingsphere.mask.config.rule.MaskTableRuleConfiguration;
28  import org.apache.shardingsphere.mask.constant.MaskOrder;
29  import org.apache.shardingsphere.mask.rule.attribute.MaskTableMapperRuleAttribute;
30  import org.apache.shardingsphere.mask.spi.MaskAlgorithm;
31  
32  import java.util.Collection;
33  import java.util.Collections;
34  import java.util.Map;
35  import java.util.Optional;
36  import java.util.concurrent.ConcurrentHashMap;
37  import java.util.concurrent.atomic.AtomicReference;
38  import java.util.stream.Collectors;
39  
40  /**
41   * Mask rule.
42   */
43  public final class MaskRule implements DatabaseRule, PartialRuleUpdateSupported<MaskRuleConfiguration> {
44      
45      private final AtomicReference<MaskRuleConfiguration> configuration = new AtomicReference<>();
46      
47      private final Map<String, MaskAlgorithm<?, ?>> maskAlgorithms = new CaseInsensitiveMap<>(Collections.emptyMap(), new ConcurrentHashMap<>());
48      
49      private final Map<String, MaskTable> tables = new CaseInsensitiveMap<>(Collections.emptyMap(), new ConcurrentHashMap<>());
50      
51      private final AtomicReference<RuleAttributes> attributes = new AtomicReference<>();
52      
53      public MaskRule(final MaskRuleConfiguration ruleConfig) {
54          configuration.set(ruleConfig);
55          ruleConfig.getMaskAlgorithms().forEach((key, value) -> maskAlgorithms.put(key, TypedSPILoader.getService(MaskAlgorithm.class, value.getType(), value.getProps())));
56          ruleConfig.getTables().forEach(each -> tables.put(each.getName(), new MaskTable(each, maskAlgorithms)));
57          attributes.set(new RuleAttributes(new MaskTableMapperRuleAttribute(tables.keySet())));
58      }
59      
60      /**
61       * Find mask table.
62       *
63       * @param tableName table name
64       * @return found mask table
65       */
66      public Optional<MaskTable> findMaskTable(final String tableName) {
67          return Optional.ofNullable(tables.get(tableName));
68      }
69      
70      @Override
71      public RuleAttributes getAttributes() {
72          return attributes.get();
73      }
74      
75      @Override
76      public MaskRuleConfiguration getConfiguration() {
77          return configuration.get();
78      }
79      
80      @Override
81      public void updateConfiguration(final MaskRuleConfiguration toBeUpdatedRuleConfig) {
82          configuration.set(toBeUpdatedRuleConfig);
83      }
84      
85      @Override
86      public boolean partialUpdate(final MaskRuleConfiguration toBeUpdatedRuleConfig) {
87          handleAddedMaskAlgorithm(toBeUpdatedRuleConfig);
88          handleRemovedMaskAlgorithm(toBeUpdatedRuleConfig);
89          Collection<String> toBeUpdatedTablesNames = toBeUpdatedRuleConfig.getTables().stream().map(MaskTableRuleConfiguration::getName).collect(Collectors.toCollection(CaseInsensitiveSet::new));
90          Collection<String> toBeRemovedTableNames = tables.keySet().stream().filter(each -> !toBeUpdatedTablesNames.contains(each)).collect(Collectors.toList());
91          if (!toBeRemovedTableNames.isEmpty()) {
92              toBeRemovedTableNames.forEach(tables::remove);
93          }
94          for (MaskTableRuleConfiguration maskTableRuleConfiguration : toBeUpdatedRuleConfig.getTables()) {
95              tables.put(maskTableRuleConfiguration.getName(), new MaskTable(maskTableRuleConfiguration, maskAlgorithms));
96              attributes.set(new RuleAttributes(new MaskTableMapperRuleAttribute(tables.keySet())));
97          }
98          return false;
99      }
100     
101     private void handleAddedMaskAlgorithm(final MaskRuleConfiguration toBeUpdatedRuleConfig) {
102         toBeUpdatedRuleConfig.getMaskAlgorithms().entrySet().stream()
103                 .filter(entry -> !maskAlgorithms.containsKey(entry.getKey()))
104                 .forEach(entry -> maskAlgorithms.computeIfAbsent(entry.getKey(), key -> TypedSPILoader.getService(MaskAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps())));
105     }
106     
107     private void handleRemovedMaskAlgorithm(final MaskRuleConfiguration toBeUpdatedRuleConfig) {
108         maskAlgorithms.entrySet().stream()
109                 .filter(entry -> !toBeUpdatedRuleConfig.getMaskAlgorithms().containsKey(entry.getKey()))
110                 .forEach(entry -> maskAlgorithms.remove(entry.getKey()));
111     }
112     
113     @Override
114     public int getOrder() {
115         return MaskOrder.ORDER;
116     }
117 }