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.datanode;
19  
20  import com.google.common.base.Objects;
21  import com.google.common.base.Splitter;
22  import lombok.Getter;
23  import lombok.RequiredArgsConstructor;
24  import lombok.Setter;
25  import lombok.ToString;
26  import org.apache.shardingsphere.infra.database.core.metadata.database.DialectDatabaseMetaData;
27  import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
28  import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
29  import org.apache.shardingsphere.infra.exception.kernel.metadata.datanode.InvalidDataNodeFormatException;
30  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
31  
32  import java.util.List;
33  
34  /**
35   * Data node.
36   */
37  @RequiredArgsConstructor
38  @Getter
39  @Setter
40  @ToString
41  public final class DataNode {
42      
43      private static final String DELIMITER = ".";
44      
45      private static final String ASTERISK = "*";
46      
47      private final String dataSourceName;
48      
49      private final String tableName;
50      
51      // TODO add final for schemaName
52      private String schemaName;
53      
54      /**
55       * Constructs a data node with well-formatted string.
56       *
57       * @param dataNode string of data node. use {@code .} to split data source name and table name.
58       */
59      public DataNode(final String dataNode) {
60          // TODO remove duplicated splitting?
61          boolean isIncludeInstance = isActualDataNodesIncludedDataSourceInstance(dataNode);
62          if (!isIncludeInstance && !isValidDataNode(dataNode, 2)) {
63              throw new InvalidDataNodeFormatException(dataNode);
64          }
65          if (isIncludeInstance && !isValidDataNode(dataNode, 3)) {
66              throw new InvalidDataNodeFormatException(dataNode);
67          }
68          List<String> segments = Splitter.on(DELIMITER).splitToList(dataNode);
69          dataSourceName = isIncludeInstance ? segments.get(0) + DELIMITER + segments.get(1) : segments.get(0);
70          tableName = segments.get(isIncludeInstance ? 2 : 1);
71      }
72      
73      /**
74       * Constructs a data node with well-formatted string.
75       *
76       * @param databaseName database name
77       * @param databaseType database type
78       * @param dataNode string of data node. use {@code .} to split data source name and table name
79       */
80      public DataNode(final String databaseName, final DatabaseType databaseType, final String dataNode) {
81          ShardingSpherePreconditions.checkState(dataNode.contains(DELIMITER), () -> new InvalidDataNodeFormatException(dataNode));
82          boolean containsSchema = isValidDataNode(dataNode, 3);
83          List<String> segments = Splitter.on(DELIMITER).splitToList(dataNode);
84          dataSourceName = segments.get(0);
85          schemaName = getSchemaName(databaseName, databaseType, containsSchema, segments);
86          tableName = containsSchema ? segments.get(2).toLowerCase() : segments.get(1).toLowerCase();
87      }
88      
89      private String getSchemaName(final String databaseName, final DatabaseType databaseType, final boolean containsSchema, final List<String> segments) {
90          DialectDatabaseMetaData dialectDatabaseMetaData = new DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData();
91          if (dialectDatabaseMetaData.getDefaultSchema().isPresent()) {
92              return containsSchema ? segments.get(1) : ASTERISK;
93          }
94          return databaseName;
95      }
96      
97      private boolean isValidDataNode(final String dataNodeStr, final Integer tier) {
98          return dataNodeStr.contains(DELIMITER) && tier == Splitter.on(DELIMITER).omitEmptyStrings().splitToList(dataNodeStr).size();
99      }
100     
101     private boolean isActualDataNodesIncludedDataSourceInstance(final String actualDataNodes) {
102         return isValidDataNode(actualDataNodes, 3);
103     }
104     
105     /**
106      * Format data node as string.
107      *
108      * @return formatted data node
109      */
110     public String format() {
111         return dataSourceName + DELIMITER + tableName;
112     }
113     
114     /**
115      * Format data node as string.
116      *
117      * @param databaseType database type
118      * @return formatted data node
119      */
120     public String format(final DatabaseType databaseType) {
121         DialectDatabaseMetaData dialectDatabaseMetaData = new DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData();
122         return dialectDatabaseMetaData.getDefaultSchema().isPresent() ? dataSourceName + DELIMITER + schemaName + DELIMITER + tableName : dataSourceName + DELIMITER + tableName;
123     }
124     
125     @Override
126     public boolean equals(final Object object) {
127         if (this == object) {
128             return true;
129         }
130         if (null == object || getClass() != object.getClass()) {
131             return false;
132         }
133         DataNode dataNode = (DataNode) object;
134         return Objects.equal(dataSourceName.toUpperCase(), dataNode.dataSourceName.toUpperCase())
135                 && Objects.equal(tableName.toUpperCase(), dataNode.tableName.toUpperCase())
136                 && Objects.equal(null == schemaName ? null : schemaName.toUpperCase(), null == dataNode.schemaName ? null : dataNode.schemaName.toUpperCase());
137     }
138     
139     @Override
140     public int hashCode() {
141         return Objects.hashCode(dataSourceName.toUpperCase(), tableName.toUpperCase(), null == schemaName ? null : schemaName.toUpperCase());
142     }
143 }