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             if (!result.containsKey(each)) {
123                 result.put(each, new LinkedHashSet<>());
124             }
125             result.get(each).add(rule.getClass());
126         }
127         return result;
128     }
129     
130     private Collection<String> getInUsedStorageUnitNames(final ShardingSphereRule rule) {
131         Optional<DataSourceMapperRuleAttribute> dataSourceMapperRuleAttribute = rule.getAttributes().findAttribute(DataSourceMapperRuleAttribute.class);
132         if (dataSourceMapperRuleAttribute.isPresent()) {
133             return getInUsedStorageUnitNames(dataSourceMapperRuleAttribute.get());
134         }
135         Optional<DataNodeRuleAttribute> dataNodeRuleAttribute = rule.getAttributes().findAttribute(DataNodeRuleAttribute.class);
136         if (dataNodeRuleAttribute.isPresent()) {
137             return getInUsedStorageUnitNames(dataNodeRuleAttribute.get());
138         }
139         return Collections.emptyList();
140     }
141     
142     private Collection<String> getInUsedStorageUnitNames(final DataSourceMapperRuleAttribute ruleAttribute) {
143         return ruleAttribute.getDataSourceMapper().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
144     }
145     
146     private Collection<String> getInUsedStorageUnitNames(final DataNodeRuleAttribute ruleAttribute) {
147         return ruleAttribute.getAllDataNodes().values().stream().flatMap(each -> each.stream().map(DataNode::getDataSourceName).collect(Collectors.toSet()).stream()).collect(Collectors.toSet());
148     }
149     
150     private void mergeInUsedStorageUnitNameAndRules(final Map<String, Collection<Class<? extends ShardingSphereRule>>> storageUnitNameAndRules,
151                                                     final Map<String, Collection<Class<? extends ShardingSphereRule>>> toBeMergedStorageUnitNameAndRules) {
152         for (Entry<String, Collection<Class<? extends ShardingSphereRule>>> entry : toBeMergedStorageUnitNameAndRules.entrySet()) {
153             if (storageUnitNameAndRules.containsKey(entry.getKey())) {
154                 for (Class<? extends ShardingSphereRule> each : entry.getValue()) {
155                     if (!storageUnitNameAndRules.get(entry.getKey()).contains(each)) {
156                         storageUnitNameAndRules.get(entry.getKey()).add(each);
157                     }
158                 }
159             } else {
160                 storageUnitNameAndRules.put(entry.getKey(), entry.getValue());
161             }
162         }
163     }
164     
165     /**
166      * Get rule attributes.
167      *
168      * @param attributeClass rule attribute class
169      * @param <T> type of rule attributes
170      * @return rule attributes
171      */
172     public <T extends RuleAttribute> Collection<T> getAttributes(final Class<T> attributeClass) {
173         Collection<T> result = new LinkedList<>();
174         for (ShardingSphereRule each : rules) {
175             each.getAttributes().findAttribute(attributeClass).ifPresent(result::add);
176         }
177         return result;
178     }
179     
180     /**
181      * Get rule attributes.
182      *
183      * @param attributeClass rule attribute class
184      * @param <T> type of rule attributes
185      * @return rule attributes
186      */
187     public <T extends RuleAttribute> Optional<T> findAttribute(final Class<T> attributeClass) {
188         for (ShardingSphereRule each : rules) {
189             if (each.getAttributes().findAttribute(attributeClass).isPresent()) {
190                 return each.getAttributes().findAttribute(attributeClass);
191             }
192         }
193         return Optional.empty();
194     }
195 }