Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.epam.eco.kafkamanager.ui.topics.TopicController Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2022 EPAM Systems
*
* 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.epam.eco.kafkamanager.ui.topics;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.epam.eco.kafkamanager.*;
import com.epam.eco.kafkamanager.ui.utils.ComboBoxModel;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.epam.eco.commons.kafka.config.TopicConfigDef;
import com.epam.eco.kafkamanager.udmetrics.UDMetric;
import com.epam.eco.kafkamanager.udmetrics.UDMetricManager;
import com.epam.eco.kafkamanager.udmetrics.UDMetricType;
import com.epam.eco.kafkamanager.ui.config.KafkaManagerUiProperties;
import com.epam.eco.kafkamanager.ui.metrics.udm.UDMetricWrapper;
import com.epam.eco.kafkamanager.ui.topics.export.TopicExporterType;
import com.epam.eco.kafkamanager.ui.topics.model.TopicInfoToModelMapper;
import com.epam.eco.kafkamanager.ui.topics.model.TopicTableModel;
import com.epam.eco.kafkamanager.ui.utils.ComboBoxModel;
import com.epam.eco.kafkamanager.ui.utils.MetadataWrapper;
import com.epam.eco.kafkamanager.utils.MapperUtils;
import static com.epam.eco.kafkamanager.ui.topics.browser.TopicBrowserController.ATTR_SCHEMA_CATALOG_URL_TEMPLATE;
/**
* @author Andrei_Tytsik
*/
@Controller
public class TopicController {
public static final String TOPICS_VIEW = "topics";
public static final String TOPIC_VIEW = "topic";
public static final String TOPIC_CREATE_VIEW = "topic_create";
public static final String TOPIC_CONFIG_UPDATE_VIEW = "topic_config_update";
public static final String TOPIC_PARTITIONS_CREATE_VIEW = "topic_partitions_create";
public static final String TOPIC_METADATA_VIEW = "topic_metadata";
public static final String ATTR_TOPIC = "topic";
public static final String ATTR_CONFIG_DEF = "configDef";
public static final String ATTR_TOPIC_OFFSET_INCREASE_UDM_TYPE = "topicOffsetIncreaseUdmType";
public static final String ATTR_TOPIC_OFFSET_INCREASE_UDM_NAME = "topicOffsetIncreaseUdmName";
public static final String ATTR_TOPIC_OFFSET_INCREASE_UDM = "topicOffsetIncreaseUdm";
public static final String ATTR_DEFAULT_PARTITION_COUNT = "defaultPartitionCount";
public static final String ATTR_DEFAULT_REPLICATION_FACTOR = "defaultReplicationFactor";
public static final String ATTR_MAX_REPLICATION_FACTOR = "maxReplicationFactor";
public static final String ATTR_REPLICATION_STATES = "replicationStates";
public static final String ATTR_METADATA = "metadata";
public static final String ATTR_DATA_CATALOG_URL_TEMPLATE = "dataCatalogUrlTemplate";
public static final String ATTR_GRAFANA_METRICS_URL_TEMPLATE = "grafanaMetricsUrlTemplate";
public static final String ATTR_EXTERNAL_TOOL_TEMPLATES = "externalToolTemplates";
public static final String ATTR_FULL_SCREEN = "fullScreen";
public static final String MAPPING_TOPICS = "/topics";
public static final String MAPPING_TOPIC_LIST = "/topic_list";
public static final String MAPPING_TOPIC = MAPPING_TOPICS + "/{name}";
public static final String MAPPING_COUNT_RECORDS = MAPPING_TOPIC + "/count_records";
public static final String MAPPING_PURGER = MAPPING_TOPIC + "/purger";
public static final String MAPPING_DELETE = MAPPING_TOPIC + "/delete";
public static final String MAPPING_CONFIG = MAPPING_TOPIC + "/config";
public static final String MAPPING_PARTITIONS = MAPPING_TOPIC + "/partitions";
public static final String MAPPING_METADATA = MAPPING_TOPIC + "/metadata";
public static final String MAPPING_EXPORT = "/topics_export";
public static final String MAPPING_CREATE = "/topic_create";
@Autowired
private KafkaAdminOperations kafkaAdminOperations;
@Autowired
private KafkaManagerUiProperties properties;
@Autowired
private KafkaManager kafkaManager;
@Autowired(required=false)
private UDMetricManager udMetricManager;
public static Map extractConfigsFromParams(
Map paramsMap,
boolean skipNulls) {
Map configs = new HashMap<>((int) Math.ceil(paramsMap.size() / 0.75));
for(Entry entry : paramsMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (TopicConfigDef.INSTANCE.key(key) == null || (skipNulls && StringUtils.isBlank(value))) {
continue;
}
configs.put(key, StringUtils.stripToNull(value));
}
return configs;
}
public static String buildTopicUrl(String topicName) {
return MAPPING_TOPIC.replace("{name}", topicName);
}
@RequestMapping(value=MAPPING_TOPICS, method = RequestMethod.GET)
public String topics( @RequestParam Map paramsMap,
Model model) {
model.addAttribute(ATTR_DATA_CATALOG_URL_TEMPLATE, properties.getDataCatalogTool());
model.addAttribute(ATTR_GRAFANA_METRICS_URL_TEMPLATE, properties.getGrafanaMetrics());
model.addAttribute(ATTR_REPLICATION_STATES,
Arrays.stream(ReplicationState.values())
.map(state-> ComboBoxModel.build(state.name()))
.collect(Collectors.toList()));
model.addAttribute(ATTR_EXTERNAL_TOOL_TEMPLATES, properties.getExternalTools());
model.addAttribute(ATTR_FULL_SCREEN, paramsMap.get(ATTR_FULL_SCREEN));
return TOPICS_VIEW;
}
@RequestMapping(value=MAPPING_TOPIC_LIST, method = RequestMethod.GET)
public @ResponseBody ResponseEntity topicList(
@RequestParam Map paramsMap) {
TopicListSearchCriteria criteria = TopicListSearchCriteria.fromJsonWith(paramsMap, kafkaManager);
List topics = kafkaManager.getTopics(criteria);
TopicInfoToModelMapper mapper =
new TopicInfoToModelMapper(properties.getDataCatalogTool(),
properties.getGrafanaMetrics(),
kafkaManager,
properties.getExternalTools());
TopicTableModel model = TopicTableModel.builder()
.draw(1)
.recordsTotal(topics.size())
.recordsFiltered(topics.size())
.data(topics.stream()
.map(mapper)
.collect(Collectors.toList()) )
.build();
return ResponseEntity.ok(model);
}
@RequestMapping(value = MAPPING_TOPIC, method = RequestMethod.GET)
public String topic(@PathVariable("name") String topicName, Model model) {
model.addAttribute(
ATTR_TOPIC,
TopicInfoWrapper.wrap(topicName, kafkaManager, kafkaAdminOperations));
String topicOffsetIncreaseUdmName = UDMetricType.TOPIC_OFFSET_INCREASE.formatName(topicName);
model.addAttribute(ATTR_TOPIC_OFFSET_INCREASE_UDM_TYPE, UDMetricType.TOPIC_OFFSET_INCREASE);
model.addAttribute(ATTR_TOPIC_OFFSET_INCREASE_UDM_NAME, topicOffsetIncreaseUdmName);
model.addAttribute(ATTR_TOPIC_OFFSET_INCREASE_UDM, getAndWrapUdm(topicOffsetIncreaseUdmName));
model.addAttribute(ATTR_DATA_CATALOG_URL_TEMPLATE, properties.getDataCatalogTool());
model.addAttribute(ATTR_GRAFANA_METRICS_URL_TEMPLATE, properties.getGrafanaMetrics());
model.addAttribute(ATTR_SCHEMA_CATALOG_URL_TEMPLATE, properties.getSchemaCatalogTool() );
model.addAttribute(ATTR_EXTERNAL_TOOL_TEMPLATES, properties.getExternalTools());
return TOPIC_VIEW;
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #topicName, 'READ')")
@RequestMapping(value=MAPPING_COUNT_RECORDS, method=RequestMethod.GET)
public @ResponseBody ResponseEntity> countRecords(
@PathVariable("name") String topicName) throws Exception {
Future future = kafkaManager.getTopicRecordCounterTaskExecutor().submit(topicName);
return ResponseEntity.ok(future.get(30, TimeUnit.SECONDS));
}
@RequestMapping(value=MAPPING_EXPORT, method=RequestMethod.GET)
public void export(
@RequestParam TopicExporterType exporterType,
@RequestParam Map paramsMap,
HttpServletResponse response) throws IOException {
TopicListSearchCriteria criteria = TopicListSearchCriteria.fromJsonWith(paramsMap, kafkaManager);
List topicInfos = kafkaManager.getTopics(criteria);
response.setContentType(exporterType.contentType());
response.setHeader(
"Content-Disposition",
String.format(
"attachment; filename=\"%s_%d.txt\"",
exporterType.name(), System.currentTimeMillis()));
try (Writer out = new BufferedWriter(
new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8))) {
exporterType.exporter().export(topicInfos, out);
out.flush();
}
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #topicName, 'WRITE')")
@RequestMapping(value=MAPPING_PURGER, method=RequestMethod.POST)
public String purger(@PathVariable("name") String topicName) throws Exception {
kafkaManager.getTopicPurgerTaskExecutor().execute(topicName);
return "redirect:" + buildTopicUrl(topicName);
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #topicName, 'DELETE')")
@RequestMapping(value=MAPPING_DELETE, method=RequestMethod.POST)
public String delete(@PathVariable("name") String topicName) {
kafkaManager.deleteTopic(topicName);
return "redirect:" + MAPPING_TOPICS;
}
@RequestMapping(value=MAPPING_CREATE, method=RequestMethod.GET)
public String create(Model model) {
model.addAttribute(ATTR_DEFAULT_PARTITION_COUNT, 1);
model.addAttribute(ATTR_DEFAULT_REPLICATION_FACTOR, kafkaAdminOperations.getDefaultReplicationFactor());
model.addAttribute(ATTR_MAX_REPLICATION_FACTOR, kafkaManager.getBrokerCount());
model.addAttribute(ATTR_CONFIG_DEF, TopicConfigDef.INSTANCE);
return TOPIC_CREATE_VIEW;
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #paramsMap.get('topicName'), 'CREATE')")
@RequestMapping(value=MAPPING_CREATE, method=RequestMethod.POST)
public String create(
@RequestParam String topicName,
@RequestParam Integer partitionCount,
@RequestParam Integer replicationFactor,
@RequestParam(required=false) String description,
@RequestParam(required=false) String attributes,
@RequestParam Map paramsMap) {
TopicCreateParams params = TopicCreateParams.builder().
topicName(topicName).
partitionCount(partitionCount).
replicationFactor(replicationFactor).
config(extractConfigsFromParams(paramsMap, true)).
description(description).
attributes(!StringUtils.isBlank(attributes) ? MapperUtils.jsonToMap(attributes) : null).
build();
TopicInfo topicInfo = kafkaManager.createTopic(params);
return "redirect:" + buildTopicUrl(topicInfo.getName());
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #topicName, 'ALTER_CONFIG')")
@RequestMapping(value=MAPPING_CONFIG, method = RequestMethod.GET)
public String config(@PathVariable("name") String topicName, Model model) {
model.addAttribute(
ATTR_TOPIC,
TopicInfoWrapper.wrap(topicName, kafkaManager, kafkaAdminOperations));
return TOPIC_CONFIG_UPDATE_VIEW;
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #paramsMap.get('topicName'), 'ALTER_CONFIG')")
@RequestMapping(value=MAPPING_CONFIG, method=RequestMethod.POST)
public String config(
@RequestParam String topicName,
@RequestParam Map paramsMap) {
TopicConfigUpdateParams params = TopicConfigUpdateParams.builder().
topicName(topicName).
config(extractConfigsFromParams(paramsMap, false)).
build();
TopicInfo topicInfo = kafkaManager.updateTopic(params);
return "redirect:" + buildTopicUrl(topicInfo.getName());
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #topicName, 'ALTER')")
@RequestMapping(value=MAPPING_PARTITIONS, method = RequestMethod.GET)
public String partitions(@PathVariable("name") String topicName, Model model) {
model.addAttribute(
ATTR_TOPIC,
TopicInfoWrapper.wrap(topicName, kafkaManager, kafkaAdminOperations));
return TOPIC_PARTITIONS_CREATE_VIEW;
}
@PreAuthorize("@authorizer.isPermitted('TOPIC', #paramsMap.get('topicName'), 'ALTER')")
@RequestMapping(value=MAPPING_PARTITIONS, method=RequestMethod.POST)
public String partitions(@RequestParam Map paramsMap) {
TopicPartitionsCreateParams params = TopicPartitionsCreateParams.fromJson(paramsMap);
TopicInfo topicInfo = kafkaManager.updateTopic(params);
return "redirect:" + buildTopicUrl(topicInfo.getName());
}
@RequestMapping(value = MAPPING_METADATA, method = RequestMethod.GET)
public String metadata(@PathVariable("name") String topicName, Model model) {
TopicInfo topicInfo = kafkaManager.getTopic(topicName);
model.addAttribute(ATTR_TOPIC, TopicInfoWrapper.wrap(topicInfo, kafkaManager, kafkaAdminOperations));
if (topicInfo.getMetadata().isPresent()) {
model.addAttribute(ATTR_METADATA, MetadataWrapper.wrap(topicInfo.getMetadata().get()));
}
return TOPIC_METADATA_VIEW;
}
@RequestMapping(value = MAPPING_METADATA, method = RequestMethod.POST)
public String metadata(String topicName, String description, String attributes) {
kafkaManager.updateTopic(
TopicMetadataUpdateParams.builder().
topicName(topicName).
description(description).
attributes(!StringUtils.isBlank(attributes) ? MapperUtils.jsonToMap(attributes) : null).
build());
return "redirect:" + buildTopicUrl(topicName);
}
@RequestMapping(value = MAPPING_METADATA, method = RequestMethod.DELETE)
public String metadata(@PathVariable("name") String topicName) {
kafkaManager.updateTopic(
TopicMetadataDeleteParams.builder().
topicName(topicName).
build());
return "redirect:" + buildTopicUrl(topicName);
}
private UDMetricWrapper getAndWrapUdm(String udmName) {
if (udMetricManager == null) {
return null;
}
UDMetric udm = udMetricManager.get(udmName);
return udm != null ? UDMetricWrapper.wrap(udm) : null;
}
}