All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.actuate.kafka.KafkaEndpoint Maven / Gradle / Ivy

The newest version!
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.sdk.toolkit.util.collection.CollUtil;
import org.zodiac.sdk.toolkit.util.lang.StrUtil;

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 && StrUtil.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 = CollUtil.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