org.zodiac.actuate.kafka.KafkaEndpoint Maven / Gradle / Ivy
package org.zodiac.actuate.kafka;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.kafka.config.KafkaListenerEndpointRegistry;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.kafka.listener.MessageListenerContainer;
import org.zodiac.commons.util.Colls;
import org.zodiac.commons.util.lang.Strings;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Stream;
@Endpoint(id = "kafka")
public class KafkaEndpoint {
protected Logger logger = LoggerFactory.getLogger(getClass());
private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry;
public KafkaEndpoint(KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry) {
this.kafkaListenerEndpointRegistry = kafkaListenerEndpointRegistry;
}
/**
* Execute operations on kafka topics.
*
* @param mode target operation mode, @see {@link OperationMode} .
* @param action target action, @see {@link OperationAction}.
* @param topics target operations.
* @return operation result
*/
@WriteOperation
public OperationResponse execOperationOnKafkaTopics(@Selector final int mode, @Selector final int action,
@Selector final String topics) {
if (kafkaListenerEndpointRegistry == null) {
return OperationResponse.success("No endpoint");
}
OperationMode opMode = OperationMode.findByCode(mode);
OperationAction opAction = OperationAction.findByCode(action);
if (OperationMode.INVALID == opMode) {
return OperationResponse.error("Parameter 'mode' should be 1(ON_ALL_TOPICS) or 2(ON_SOME_TOPICS)");
}
if (OperationAction.INVALID == opAction) {
return OperationResponse.error("Parameter 'action' should be 1(START) or 2(STOP)");
}
if (OperationMode.ON_SOME_TOPICS == opMode && Strings.isEmpty(topics)) {
return OperationResponse.error("Parameter 'topics' should be not null or empty");
}
Collection listenerContainers =
kafkaListenerEndpointRegistry.getAllListenerContainers();
try {
if (OperationAction.START_ACTION == opAction) {
listenerContainers
.forEach(messageListenerContainer -> enableKafkaTopicIfNecessary(messageListenerContainer, opMode,
topics.split(",")));
} else {
listenerContainers
.forEach(messageListenerContainer -> disableKafkaTopicIfNecessary(messageListenerContainer, opMode,
topics.split(",")));
}
} catch (Exception e) {
logger.error("Got execOperationOnKafkaTopics error for (mode:{}, topics:{}, action:{})", mode, topics,
action);
return OperationResponse.error("Unknown error");
}
return OperationResponse.success("Operation success");
}
private void enableKafkaTopicIfNecessary(MessageListenerContainer messageListenerContainer, OperationMode opMode,
String... topics) {
if (isMatch(opMode, messageListenerContainer.getContainerProperties(), topics)
&& !messageListenerContainer.isRunning()) {
messageListenerContainer.start();
if (messageListenerContainer.isContainerPaused()) {
messageListenerContainer.resume();
}
}
}
private void disableKafkaTopicIfNecessary(MessageListenerContainer messageListenerContainer, OperationMode opMode,
String... topics) {
if (isMatch(opMode, messageListenerContainer.getContainerProperties(), topics)
&& messageListenerContainer.isRunning()) {
messageListenerContainer.stop();
}
}
private boolean isMatch(OperationMode opMode, ContainerProperties containerProperties, String... topics) {
if (OperationMode.ON_ALL_TOPICS == opMode) {
return true;
}
Stream s1 = Stream.of(topics);
final Set s2 = Colls.set(containerProperties.getTopics());
return s1.filter(s -> s2.contains(s)).findFirst().isPresent();
}
public static enum OperationMode {
ON_ALL_TOPICS(1, "Execute operation on all topics"), ON_SOME_TOPICS(2, "Execute operation on some topics"),
INVALID(-1, "Invalid mode");
OperationMode(int code, String desc) {
this.code = code;
this.desc = desc;
}
private int code;
private String desc;
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
public static OperationMode findByCode(int code) {
for (OperationMode mode : values()) {
if (mode.getCode() == code) {
return mode;
}
}
return INVALID;
}
}
public static enum OperationAction {
START_ACTION(1, "Start message listeners on topics"), STOP_ACTION(2, "Stop message listeners on topics"),
INVALID(-1, "Invalid action");
OperationAction(int code, String desc) {
this.code = code;
this.desc = desc;
}
private int code;
private String desc;
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
public static OperationAction findByCode(int code) {
for (OperationAction mode : values()) {
if (mode.getCode() == code) {
return mode;
}
}
return INVALID;
}
}
public static class OperationResponse {
/**
* Status code for operation response(1-success,0-failed).
*/
private int code = 1;
/**
* Message for operation response.
*/
private String msg;
public OperationResponse(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
/**
* Build error response.
*
* @param msg message
* @return operation result
*/
public static OperationResponse error(String msg) {
return new OperationResponse(0, msg);
}
/**
* Build success response.
*
* @param msg message
* @return operation result
*/
public static OperationResponse success(String msg) {
return new OperationResponse(1, msg);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy