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.proxy.backend.handler.distsql.ral.queryable;
19  
20  import org.apache.commons.codec.binary.Base64;
21  import org.apache.shardingsphere.distsql.handler.engine.query.DistSQLQueryExecutor;
22  import org.apache.shardingsphere.distsql.statement.ral.queryable.export.ExportMetaDataStatement;
23  import org.apache.shardingsphere.globalclock.provider.GlobalClockProvider;
24  import org.apache.shardingsphere.globalclock.rule.GlobalClockRule;
25  import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
26  import org.apache.shardingsphere.infra.merge.result.impl.local.LocalDataQueryResultRow;
27  import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
28  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
29  import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader;
30  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
31  import org.apache.shardingsphere.infra.util.json.JsonUtils;
32  import org.apache.shardingsphere.infra.util.yaml.YamlEngine;
33  import org.apache.shardingsphere.infra.yaml.config.swapper.rule.YamlRuleConfigurationSwapper;
34  import org.apache.shardingsphere.mode.manager.ContextManager;
35  import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
36  import org.apache.shardingsphere.proxy.backend.distsql.export.ExportedClusterInfo;
37  import org.apache.shardingsphere.proxy.backend.distsql.export.ExportedMetaData;
38  import org.apache.shardingsphere.proxy.backend.distsql.export.ExportedSnapshotInfo;
39  import org.apache.shardingsphere.proxy.backend.util.ExportUtils;
40  
41  import java.time.LocalDateTime;
42  import java.util.Arrays;
43  import java.util.Collection;
44  import java.util.Collections;
45  import java.util.LinkedHashMap;
46  import java.util.Map;
47  import java.util.Map.Entry;
48  import java.util.Properties;
49  
50  /**
51   * Export metadata executor.
52   */
53  public final class ExportMetaDataExecutor implements DistSQLQueryExecutor<ExportMetaDataStatement> {
54      
55      @Override
56      public Collection<String> getColumnNames(final ExportMetaDataStatement sqlStatement) {
57          return Arrays.asList("id", "create_time", "cluster_info");
58      }
59      
60      @Override
61      public Collection<LocalDataQueryResultRow> getRows(final ExportMetaDataStatement sqlStatement, final ContextManager contextManager) {
62          String exportedData = generateExportData(contextManager.getMetaDataContexts().getMetaData());
63          if (sqlStatement.getFilePath().isPresent()) {
64              String filePath = sqlStatement.getFilePath().get();
65              ExportUtils.exportToFile(filePath, exportedData);
66              return Collections.singleton(new LocalDataQueryResultRow(contextManager.getInstanceContext().getInstance().getCurrentInstanceId(), LocalDateTime.now(),
67                      String.format("Successfully exported to:'%s'", filePath)));
68          }
69          return Collections.singleton(new LocalDataQueryResultRow(
70                  contextManager.getInstanceContext().getInstance().getCurrentInstanceId(), LocalDateTime.now(), Base64.encodeBase64String(exportedData.getBytes())));
71      }
72      
73      private String generateExportData(final ShardingSphereMetaData metaData) {
74          ProxyContext proxyContext = ProxyContext.getInstance();
75          ExportedMetaData exportedMetaData = new ExportedMetaData();
76          exportedMetaData.setDatabases(getDatabases(proxyContext));
77          exportedMetaData.setProps(generatePropsData(metaData.getProps().getProps()));
78          exportedMetaData.setRules(generateRulesData(metaData.getGlobalRuleMetaData().getConfigurations()));
79          ExportedClusterInfo exportedClusterInfo = new ExportedClusterInfo();
80          exportedClusterInfo.setMetaData(exportedMetaData);
81          generateSnapshotInfo(metaData, exportedClusterInfo);
82          return JsonUtils.toJsonString(exportedClusterInfo);
83      }
84      
85      private Map<String, String> getDatabases(final ProxyContext proxyContext) {
86          Map<String, String> result = new LinkedHashMap<>();
87          proxyContext.getAllDatabaseNames().forEach(each -> {
88              ShardingSphereDatabase database = proxyContext.getContextManager().getDatabase(each);
89              if (database.getResourceMetaData().getAllInstanceDataSourceNames().isEmpty()) {
90                  return;
91              }
92              result.put(each, ExportUtils.generateExportDatabaseData(database));
93          });
94          return result;
95      }
96      
97      private String generatePropsData(final Properties props) {
98          if (props.isEmpty()) {
99              return "";
100         }
101         StringBuilder result = new StringBuilder();
102         result.append("props:").append(System.lineSeparator());
103         props.forEach((key, value) -> result.append("  ").append(key).append(": ").append(value).append(System.lineSeparator()));
104         return result.toString();
105     }
106     
107     @SuppressWarnings({"rawtypes", "unchecked"})
108     private String generateRulesData(final Collection<RuleConfiguration> rules) {
109         if (rules.isEmpty()) {
110             return "";
111         }
112         StringBuilder result = new StringBuilder();
113         result.append("rules:").append(System.lineSeparator());
114         for (Entry<RuleConfiguration, YamlRuleConfigurationSwapper> entry : OrderedSPILoader.getServices(YamlRuleConfigurationSwapper.class, rules).entrySet()) {
115             result.append(YamlEngine.marshal(Collections.singletonList(entry.getValue().swapToYamlConfiguration(entry.getKey()))));
116         }
117         return result.toString();
118     }
119     
120     private void generateSnapshotInfo(final ShardingSphereMetaData metaData, final ExportedClusterInfo exportedClusterInfo) {
121         GlobalClockRule globalClockRule = metaData.getGlobalRuleMetaData().getSingleRule(GlobalClockRule.class);
122         if (globalClockRule.getConfiguration().isEnabled()) {
123             GlobalClockProvider globalClockProvider = TypedSPILoader.getService(GlobalClockProvider.class,
124                     globalClockRule.getGlobalClockProviderType(), globalClockRule.getConfiguration().getProps());
125             long csn = globalClockProvider.getCurrentTimestamp();
126             ExportedSnapshotInfo snapshotInfo = new ExportedSnapshotInfo();
127             snapshotInfo.setCsn(String.valueOf(csn));
128             snapshotInfo.setCreateTime(LocalDateTime.now());
129             exportedClusterInfo.setSnapshotInfo(snapshotInfo);
130         }
131     }
132     
133     @Override
134     public Class<ExportMetaDataStatement> getType() {
135         return ExportMetaDataStatement.class;
136     }
137 }