/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.linkedin.pinot.common.config;
import com.linkedin.pinot.common.utils.CommonConstants.Helix.TableType;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.configuration.ConfigurationRuntimeException;
import org.apache.helix.ZNRecord;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractTableConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTableConfig.class);
private static final String TABLE_TYPE_REALTIME = "realtime";
protected String tableName;
protected String tableType;
protected SegmentsValidationAndRetentionConfig validationConfig;
protected TenantConfig tenantConfig;
protected TableCustomConfig customConfigs;
protected @Nullable QuotaConfig quotaConfig;
protected AbstractTableConfig(String tableName, String tableType,
SegmentsValidationAndRetentionConfig validationConfig, TenantConfig tenantConfig, TableCustomConfig customConfigs,
@Nullable QuotaConfig quotaConfig) {
this.tableName = TableNameBuilder.forType(TableType.valueOf(tableType.toUpperCase())).tableNameWithType(tableName);
this.tableType = tableType;
this.validationConfig = validationConfig;
this.tenantConfig = tenantConfig;
this.customConfigs = customConfigs;
this.quotaConfig = quotaConfig;
}
public static AbstractTableConfig init(String jsonString) throws JSONException, IOException {
JSONObject tableJson = new JSONObject(jsonString);
String tableType = tableJson.getString("tableType").toLowerCase();
String tableName = TableNameBuilder.forType(TableType.valueOf(tableType.toUpperCase()))
.tableNameWithType(tableJson.getString("tableName"));
SegmentsValidationAndRetentionConfig validationConfig =
loadSegmentsConfig(new ObjectMapper().readTree(tableJson.getJSONObject("segmentsConfig").toString()));
TenantConfig tenantConfig = loadTenantsConfig(new ObjectMapper().readTree(tableJson.getJSONObject("tenants").toString()));
TableCustomConfig customConfig =
loadCustomConfig(new ObjectMapper().readTree(tableJson.getJSONObject("metadata").toString()));
IndexingConfig indexingConfig =
loadIndexingConfig(new ObjectMapper().readTree(tableJson.getJSONObject("tableIndexConfig").toString()));
QuotaConfig quotaConfig = null;
if (tableJson.has(QuotaConfig.QUOTA_SECTION_NAME)) {
try {
quotaConfig = loadQuotaConfig(
new ObjectMapper().readTree(tableJson.getJSONObject(QuotaConfig.QUOTA_SECTION_NAME).toString()));
} catch(ConfigurationRuntimeException e) {
LOGGER.error("Invalid quota configuration value for table: {}", tableName);
throw e;
}
}
if (tableType.equals("offline")) {
return new OfflineTableConfig(tableName, tableType, validationConfig, tenantConfig, customConfig, indexingConfig, quotaConfig);
} else if (tableType.equals(TABLE_TYPE_REALTIME)) {
return new RealtimeTableConfig(tableName, tableType, validationConfig, tenantConfig, customConfig, indexingConfig, quotaConfig);
}
throw new UnsupportedOperationException("unknown tableType : " + tableType);
}
public static AbstractTableConfig fromZnRecord(ZNRecord record) throws JsonParseException, JsonMappingException,
JsonProcessingException, JSONException, IOException {
Map<String, String> simpleFields = record.getSimpleFields();
JSONObject str = new JSONObject();
str.put("tableName", simpleFields.get("tableName"));
str.put("tableType", simpleFields.get("tableType"));
str.put("segmentsConfig", new JSONObject(simpleFields.get("segmentsConfig")));
str.put("tenants", new JSONObject(simpleFields.get("tenants")));
str.put("tableIndexConfig", new JSONObject(simpleFields.get("tableIndexConfig")));
str.put("metadata", new JSONObject(simpleFields.get("metadata")));
String quotaConfig = simpleFields.get(QuotaConfig.QUOTA_SECTION_NAME);
if (quotaConfig != null) {
str.put(QuotaConfig.QUOTA_SECTION_NAME, new JSONObject(quotaConfig));
}
return init(str.toString());
}
public static ZNRecord toZnRecord(AbstractTableConfig config) throws JsonGenerationException, JsonMappingException,
IOException {
ZNRecord rec = new ZNRecord(config.getTableName());
Map<String, String> rawMap = new HashMap<String, String>();
rawMap.put("tableName", config.getTableName());
rawMap.put("tableType", config.getTableType());
rawMap.put("segmentsConfig", new ObjectMapper().writeValueAsString(config.getValidationConfig()));
rawMap.put("tenants", new ObjectMapper().writeValueAsString(config.getTenantConfig()));
rawMap.put("metadata", new ObjectMapper().writeValueAsString(config.getCustomConfigs()));
rawMap.put("tableIndexConfig", new ObjectMapper().writeValueAsString(config.getIndexingConfig()));
if (config.quotaConfig != null) {
rawMap.put("quota", new ObjectMapper().writeValueAsString(config.getQuotaConfig()));
}
rec.setSimpleFields(rawMap);
return rec;
}
public static SegmentsValidationAndRetentionConfig loadSegmentsConfig(JsonNode node) throws JsonParseException,
JsonMappingException, IOException {
return new ObjectMapper().readValue(node, SegmentsValidationAndRetentionConfig.class);
}
public static TenantConfig loadTenantsConfig(JsonNode node) throws JsonParseException, JsonMappingException,
IOException {
return new ObjectMapper().readValue(node, TenantConfig.class);
}
public static TableCustomConfig loadCustomConfig(JsonNode node) throws JsonParseException, JsonMappingException,
IOException {
return new ObjectMapper().readValue(node, TableCustomConfig.class);
}
public static IndexingConfig loadIndexingConfig(JsonNode node) throws JsonParseException, JsonMappingException,
IOException {
return new ObjectMapper().readValue(node, IndexingConfig.class);
}
private static QuotaConfig loadQuotaConfig(JsonNode jsonNode)
throws IOException {
QuotaConfig quotaConfig = new ObjectMapper().readValue(jsonNode, QuotaConfig.class);
quotaConfig.validate();
return quotaConfig;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public void setTableType(String tableType) {
this.tableType = tableType;
}
public void setValidationConfig(SegmentsValidationAndRetentionConfig validationConfig) {
this.validationConfig = validationConfig;
}
public void setTenantConfig(TenantConfig tenantConfig) {
this.tenantConfig = tenantConfig;
}
public void setCustomConfigs(TableCustomConfig customConfigs) {
this.customConfigs = customConfigs;
}
public void setQuotaConfig(@Nullable QuotaConfig quotaConfig) {
this.quotaConfig = quotaConfig;
}
public String getTableName() {
return tableName;
}
public String getTableType() {
return tableType;
}
public boolean isRealTime() {
return tableType.equalsIgnoreCase(TABLE_TYPE_REALTIME);
}
public SegmentsValidationAndRetentionConfig getValidationConfig() {
return validationConfig;
}
public TenantConfig getTenantConfig() {
return tenantConfig;
}
public TableCustomConfig getCustomConfigs() {
return customConfigs;
}
public abstract IndexingConfig getIndexingConfig();
public @Nullable QuotaConfig getQuotaConfig() {
return quotaConfig;
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
result.append("tableName:" + tableName + "\n");
result.append("tableType:" + tableType + "\n");
result.append("tenant : " + tenantConfig.toString() + " \n");
result.append("segments : " + validationConfig.toString() + "\n");
result.append("customConfigs : " + customConfigs.toString() + "\n");
if (quotaConfig != null) {
result.append("quota : " + quotaConfig.toString() + "\n");
}
return result.toString();
}
public JSONObject toJSON() throws JSONException, JsonGenerationException, JsonMappingException, IOException {
JSONObject ret = new JSONObject();
ret.put("tableName", tableName);
ret.put("tableType", tableType);
ret.put("segmentsConfig", new JSONObject(new ObjectMapper().writeValueAsString(validationConfig)));
ret.put("tenants", new JSONObject(new ObjectMapper().writeValueAsString(tenantConfig)));
ret.put("tableIndexConfig", new JSONObject(new ObjectMapper().writeValueAsString(getIndexingConfig())));
ret.put("metadata", new JSONObject(new ObjectMapper().writeValueAsString(customConfigs)));
if (quotaConfig != null) {
ret.put("quota", new JSONObject(new ObjectMapper().writeValueAsString(quotaConfig)));
}
return ret;
}
}