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.datasource.pool.props.domain;
19  
20  import com.google.common.base.CaseFormat;
21  import com.google.common.base.Objects;
22  import lombok.Getter;
23  import org.apache.shardingsphere.infra.datasource.pool.metadata.DataSourcePoolMetaData;
24  import org.apache.shardingsphere.infra.datasource.pool.props.domain.custom.CustomDataSourcePoolProperties;
25  import org.apache.shardingsphere.infra.datasource.pool.props.domain.synonym.ConnectionPropertySynonyms;
26  import org.apache.shardingsphere.infra.datasource.pool.props.domain.synonym.PoolPropertySynonyms;
27  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
28  
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.LinkedHashMap;
32  import java.util.LinkedList;
33  import java.util.Map;
34  import java.util.Map.Entry;
35  import java.util.Optional;
36  
37  /**
38   * Data source pool properties.
39   */
40  @Getter
41  public final class DataSourcePoolProperties {
42      
43      private static final String UNDERSCORE = "_";
44      
45      private final String poolClassName;
46      
47      private final ConnectionPropertySynonyms connectionPropertySynonyms;
48      
49      private final PoolPropertySynonyms poolPropertySynonyms;
50      
51      private final CustomDataSourcePoolProperties customProperties;
52      
53      public DataSourcePoolProperties(final String poolClassName, final Map<String, Object> props) {
54          Optional<DataSourcePoolMetaData> metaData = TypedSPILoader.findService(DataSourcePoolMetaData.class, poolClassName);
55          this.poolClassName = metaData.map(optional -> optional.getType().toString()).orElse(poolClassName);
56          Map<String, String> propertySynonyms = metaData.map(DataSourcePoolMetaData::getPropertySynonyms).orElse(Collections.emptyMap());
57          Map<String, Object> effectiveProps = convertToCamelKeys(props);
58          connectionPropertySynonyms = new ConnectionPropertySynonyms(effectiveProps, propertySynonyms);
59          poolPropertySynonyms = new PoolPropertySynonyms(effectiveProps, propertySynonyms);
60          Collection<String> transientFieldNames = metaData.map(DataSourcePoolMetaData::getTransientFieldNames).orElse(Collections.emptyList());
61          customProperties = new CustomDataSourcePoolProperties(effectiveProps, getStandardPropertyKeys(), transientFieldNames, propertySynonyms);
62      }
63      
64      private Map<String, Object> convertToCamelKeys(final Map<String, Object> props) {
65          Map<String, Object> result = new LinkedHashMap<>(props.size(), 1F);
66          for (Entry<String, Object> entry : props.entrySet()) {
67              result.put(entry.getKey().contains(UNDERSCORE) ? CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.getKey()) : entry.getKey(), entry.getValue());
68          }
69          return result;
70      }
71      
72      private Collection<String> getStandardPropertyKeys() {
73          Collection<String> result = new LinkedList<>(connectionPropertySynonyms.getStandardPropertyKeys());
74          result.addAll(poolPropertySynonyms.getStandardPropertyKeys());
75          return result;
76      }
77      
78      /**
79       * Get all standard properties.
80       *
81       * @return all standard properties
82       */
83      public Map<String, Object> getAllStandardProperties() {
84          Map<String, Object> result = new LinkedHashMap<>(
85                  connectionPropertySynonyms.getStandardProperties().size() + poolPropertySynonyms.getStandardProperties().size() + customProperties.getProperties().size(), 1F);
86          result.putAll(connectionPropertySynonyms.getStandardProperties());
87          result.putAll(poolPropertySynonyms.getStandardProperties());
88          result.putAll(customProperties.getProperties());
89          return result;
90      }
91      
92      /**
93       * Get all local properties.
94       *
95       * @return all local properties
96       */
97      public Map<String, Object> getAllLocalProperties() {
98          Map<String, Object> result = new LinkedHashMap<>(
99                  connectionPropertySynonyms.getLocalProperties().size() + poolPropertySynonyms.getLocalProperties().size() + customProperties.getProperties().size(), 1F);
100         result.putAll(connectionPropertySynonyms.getLocalProperties());
101         result.putAll(poolPropertySynonyms.getLocalProperties());
102         result.putAll(customProperties.getProperties());
103         return result;
104     }
105     
106     @Override
107     public boolean equals(final Object obj) {
108         return this == obj || null != obj && getClass() == obj.getClass() && equalsByProperties((DataSourcePoolProperties) obj);
109     }
110     
111     private boolean equalsByProperties(final DataSourcePoolProperties props) {
112         return poolClassName.equals(props.poolClassName) && equalsByLocalProperties(props.getAllLocalProperties());
113     }
114     
115     private boolean equalsByLocalProperties(final Map<String, Object> localProps) {
116         for (Entry<String, Object> entry : getAllLocalProperties().entrySet()) {
117             if (!localProps.containsKey(entry.getKey())) {
118                 continue;
119             }
120             if (entry.getValue() instanceof Map) {
121                 return entry.getValue().equals(localProps.get(entry.getKey()));
122             }
123             if (!String.valueOf(entry.getValue()).equals(String.valueOf(localProps.get(entry.getKey())))) {
124                 return false;
125             }
126         }
127         return true;
128     }
129     
130     @Override
131     public int hashCode() {
132         StringBuilder stringBuilder = new StringBuilder();
133         for (Entry<String, Object> entry : getAllLocalProperties().entrySet()) {
134             stringBuilder.append(entry.getKey()).append(entry.getValue());
135         }
136         return Objects.hashCode(poolClassName, stringBuilder.toString());
137     }
138 }