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