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.infra.metadata.database.rule;
19  
20  import com.google.common.base.Preconditions;
21  import lombok.Getter;
22  import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
23  import org.apache.shardingsphere.infra.datanode.DataNode;
24  import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
25  import org.apache.shardingsphere.infra.rule.attribute.RuleAttribute;
26  import org.apache.shardingsphere.infra.rule.attribute.datanode.DataNodeRuleAttribute;
27  import org.apache.shardingsphere.infra.rule.attribute.datasource.DataSourceMapperRuleAttribute;
28  
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.LinkedHashMap;
32  import java.util.LinkedHashSet;
33  import java.util.LinkedList;
34  import java.util.Map;
35  import java.util.Map.Entry;
36  import java.util.Optional;
37  import java.util.concurrent.CopyOnWriteArrayList;
38  import java.util.stream.Collectors;
39  
40  /**
41   * Rule meta data.
42   */
43  @Getter
44  public final class RuleMetaData {
45      
46      private final Collection<ShardingSphereRule> rules;
47      
48      public RuleMetaData(final Collection<ShardingSphereRule> rules) {
49          this.rules = new CopyOnWriteArrayList<>(rules);
50      }
51      
52      /**
53       * Get rule configurations.
54       *
55       * @return got rule configurations
56       */
57      public Collection<RuleConfiguration> getConfigurations() {
58          return rules.stream().map(ShardingSphereRule::getConfiguration).collect(Collectors.toList());
59      }
60      
61      /**
62       * Find rules by class.
63       *
64       * @param clazz target class
65       * @param <T> type of rule
66       * @return found rules
67       */
68      public <T extends ShardingSphereRule> Collection<T> findRules(final Class<T> clazz) {
69          Collection<T> result = new LinkedList<>();
70          for (ShardingSphereRule each : rules) {
71              if (clazz.isAssignableFrom(each.getClass())) {
72                  result.add(clazz.cast(each));
73              }
74          }
75          return result;
76      }
77      
78      /**
79       * Find single rule by class.
80       *
81       * @param clazz target class
82       * @param <T> type of rule
83       * @return found single rule
84       */
85      public <T extends ShardingSphereRule> Optional<T> findSingleRule(final Class<T> clazz) {
86          Collection<T> foundRules = findRules(clazz);
87          return foundRules.isEmpty() ? Optional.empty() : Optional.of(foundRules.iterator().next());
88      }
89      
90      /**
91       * Get single rule by class.
92       *
93       * @param clazz target class
94       * @param <T> type of rule
95       * @return found single rule
96       */
97      public <T extends ShardingSphereRule> T getSingleRule(final Class<T> clazz) {
98          Collection<T> foundRules = findRules(clazz);
99          Preconditions.checkState(1 == foundRules.size(), "Rule `%s` should have and only have one instance.", clazz.getSimpleName());
100         return foundRules.iterator().next();
101     }
102     
103     /**
104      * Get in used storage units name and used rule classes map.
105      *
106      * @return in used storage units name and used rule classes map
107      */
108     public Map<String, Collection<Class<? extends ShardingSphereRule>>> getInUsedStorageUnitNameAndRulesMap() {
109         Map<String, Collection<Class<? extends ShardingSphereRule>>> result = new LinkedHashMap<>();
110         for (ShardingSphereRule each : rules) {
111             Collection<String> inUsedStorageUnitNames = getInUsedStorageUnitNames(each);
112             if (!inUsedStorageUnitNames.isEmpty()) {
113                 mergeInUsedStorageUnitNameAndRules(result, getInUsedStorageUnitNameAndRulesMap(each, inUsedStorageUnitNames));
114             }
115         }
116         return result;
117     }
118     
119     private Map<String, Collection<Class<? extends ShardingSphereRule>>> getInUsedStorageUnitNameAndRulesMap(final ShardingSphereRule rule, final Collection<String> inUsedStorageUnitNames) {
120         Map<String, Collection<Class<? extends ShardingSphereRule>>> result = new LinkedHashMap<>();
121         for (String each : inUsedStorageUnitNames) {
122             result.computeIfAbsent(each, unused -> new LinkedHashSet<>()).add(rule.getClass());
123         }
124         return result;
125     }
126     
127     private Collection<String> getInUsedStorageUnitNames(final ShardingSphereRule rule) {
128         Optional<DataSourceMapperRuleAttribute> dataSourceMapperRuleAttribute = rule.getAttributes().findAttribute(DataSourceMapperRuleAttribute.class);
129         if (dataSourceMapperRuleAttribute.isPresent()) {
130             return getInUsedStorageUnitNames(dataSourceMapperRuleAttribute.get());
131         }
132         Optional<DataNodeRuleAttribute> dataNodeRuleAttribute = rule.getAttributes().findAttribute(DataNodeRuleAttribute.class);
133         if (dataNodeRuleAttribute.isPresent()) {
134             return getInUsedStorageUnitNames(dataNodeRuleAttribute.get());
135         }
136         return Collections.emptyList();
137     }
138     
139     private Collection<String> getInUsedStorageUnitNames(final DataSourceMapperRuleAttribute ruleAttribute) {
140         return ruleAttribute.getDataSourceMapper().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
141     }
142     
143     private Collection<String> getInUsedStorageUnitNames(final DataNodeRuleAttribute ruleAttribute) {
144         return ruleAttribute.getAllDataNodes().values().stream().flatMap(each -> each.stream().map(DataNode::getDataSourceName).collect(Collectors.toSet()).stream()).collect(Collectors.toSet());
145     }
146     
147     private void mergeInUsedStorageUnitNameAndRules(final Map<String, Collection<Class<? extends ShardingSphereRule>>> storageUnitNameAndRules,
148                                                     final Map<String, Collection<Class<? extends ShardingSphereRule>>> toBeMergedStorageUnitNameAndRules) {
149         for (Entry<String, Collection<Class<? extends ShardingSphereRule>>> entry : toBeMergedStorageUnitNameAndRules.entrySet()) {
150             if (storageUnitNameAndRules.containsKey(entry.getKey())) {
151                 for (Class<? extends ShardingSphereRule> each : entry.getValue()) {
152                     if (!storageUnitNameAndRules.get(entry.getKey()).contains(each)) {
153                         storageUnitNameAndRules.get(entry.getKey()).add(each);
154                     }
155                 }
156             } else {
157                 storageUnitNameAndRules.put(entry.getKey(), entry.getValue());
158             }
159         }
160     }
161     
162     /**
163      * Get rule attributes.
164      *
165      * @param attributeClass rule attribute class
166      * @param <T> type of rule attributes
167      * @return rule attributes
168      */
169     public <T extends RuleAttribute> Collection<T> getAttributes(final Class<T> attributeClass) {
170         Collection<T> result = new LinkedList<>();
171         for (ShardingSphereRule each : rules) {
172             each.getAttributes().findAttribute(attributeClass).ifPresent(result::add);
173         }
174         return result;
175     }
176     
177     /**
178      * Get rule attributes.
179      *
180      * @param attributeClass rule attribute class
181      * @param <T> type of rule attributes
182      * @return rule attributes
183      */
184     public <T extends RuleAttribute> Optional<T> findAttribute(final Class<T> attributeClass) {
185         for (ShardingSphereRule each : rules) {
186             if (each.getAttributes().findAttribute(attributeClass).isPresent()) {
187                 return each.getAttributes().findAttribute(attributeClass);
188             }
189         }
190         return Optional.empty();
191     }
192 }