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

org.sdn.api.event.MessageEvent Maven / Gradle / Ivy

package org.sdn.api.event;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.sdn.api.DefaultOpenClient;
import org.sdn.api.OpenApiException;
import org.sdn.api.domain.OpenClientDO;
import org.sdn.api.request.SubscribeEventRequest;
import org.sdn.api.response.SubscribeEventResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.*;


/**
 * User: humucai
 * Date: 2018/11/27
 * Time: 18:28
 */
public class MessageEvent implements BeanPostProcessor {

    private static final Logger LOG = LoggerFactory.getLogger(MessageEvent.class);

    private Object instance;

    private Method method;

    private static Map executors = new HashMap<>();

    private static Map> groups = new HashMap<>();

    private static boolean isInit = false;

    private static MessageEvent defaultExecutor;

    private static Listener listener;

    private MessageEvent(Object instance, Method method) {
        this.instance = instance;
        this.method = method;
    }

    public MessageEvent() {
    }

    public synchronized static void start(DefaultOpenClient client, String accessToken) throws OpenApiException {
        if (isInit) {
            return;
        }
        isInit = true;
        subscribeEvent(client, accessToken);
        startEventListener();
    }


    // 订阅事件
    private static void subscribeEvent(DefaultOpenClient client, String accessToken) throws OpenApiException {
        OpenClientDO openClientDO = client.getOpenClientDO();
        String authEvent = openClientDO.getAuthEvent();
        if (isNullOrEmpty(authEvent) || isNullOrEmpty(accessToken)) {
            return;
        }
        try {
            JSONObject o = JSON.parseObject(authEvent);
            List> ps = new ArrayList<>();

            String groupId = openClientDO.getAppSecret();
            for (String key : o.keySet()) {
                JSONObject ob = o.getJSONObject(key);
                JSONObject condition = ob.getJSONObject("condition");
                String server = condition.getString("server");
                String username = condition.getString("username");
                String password = condition.getString("password");

                Conn conn = new Conn(server, groupId, username, password);

                if (!groups.containsKey(conn)) {
                    List topics = new ArrayList<>();
                    topics.add(key);
                    groups.put(conn, topics);
                } else {
                    groups.get(conn).add(key);
                }

                String event = ob.getString("event");
                if (event != null) {
                    JSONArray sub = condition.getJSONArray("sub");
                    sub.forEach((x) -> {
                        Map param = new HashMap<>();
                        try {
                            param.put("servicename", key);
                            JSONObject simpleObj = (JSONObject) x;
                            simpleObj.forEach((k, v) -> {
                                if (v instanceof JSONArray) {
                                    ArrayList> eventList = new ArrayList();
                                    ((JSONArray) v).forEach((obj) -> {
                                        HashMap m = new HashMap();
                                        ((JSONObject) obj).forEach((sk, sv) -> {
                                            String s;
                                            if (sv instanceof  JSONObject){
                                               s = ((JSONObject) sv).toJSONString();
                                            }else {
                                                s = sv.toString();
                                            }
                                            m.put(sk, s);
                                        });
                                        eventList.add(m);
                                    });
                                    param.put(k, eventList);
                                } else {
                                    param.put(k, v.toString());
                                }
                            });
                        } catch (Exception e) {
                            LOG.warn("parse error : {}", authEvent);
                        }
                        ps.add(param);
                    });
                }
            }
            for (Map p : ps) {
                SubscribeEventRequest request = new SubscribeEventRequest(p);
                SubscribeEventResponse response = client.defaultExecute(request, accessToken);
                if (response.isSuccess()) {
                    if (!response.isOk()) {
                        throw new OpenApiException("subscribe event error");
                    }
                }
            }
        } catch (Exception e) {
            throw new OpenApiException("subscribe event error", e);
        }
    }

    private static void startEventListener() {
        groups.forEach((conn, topics) -> new Thread(new EventConsumerRunner(conn, topics)).start());
    }


    public static void setListener(Listener l) {
        listener = l;
    }


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
        for (Method m : methods) {
            EventListener eventListener = AnnotationUtils.findAnnotation(m, EventListener.class);
            if (eventListener == null) {
                continue;
            }

            String v = eventListener.value();
            String stringType = "java.lang.String";
            Class[] parameterTypes = m.getParameterTypes();
            if (isNullOrEmpty(v)) {
                if (parameterTypes.length > 1 &&
                        Objects.equals(parameterTypes[0].getName(), stringType) &&
                        Objects.equals(parameterTypes[1].getName(), stringType)) {
                    defaultExecutor = new MessageEvent(bean, m);
                }
            } else {
                if (parameterTypes.length < 1 ||
                        !Objects.equals(parameterTypes[0].getName(), stringType)) {
                    continue;
                }
                if (!isNullOrEmpty(v)) {
                    executors.put(v, new MessageEvent(bean, m));
                }
            }
        }

        return bean;
    }


    private static boolean isNullOrEmpty(String s) {
        return s == null || s.trim().equals("");
    }


    private static class Conn {
        String servers;
        String groupId;
        String username;
        String password;

        Conn(String servers, String groupId, String username, String password) {
            this.servers = org.sdn.api.utils.StringUtils.parseServers(servers);
            this.groupId = groupId;
            this.username = username;
            this.password = password;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Conn conn = (Conn) o;
            return Objects.equals(servers, conn.servers) &&
                    Objects.equals(groupId, conn.groupId) &&
                    Objects.equals(username, conn.username) &&
                    Objects.equals(password, conn.password);
        }

        @Override
        public int hashCode() {
            return Objects.hash(servers, groupId, username, password);
        }
    }


    private static class EventConsumerRunner implements Runnable {

        private Conn conn;
        private List topics;

        EventConsumerRunner(Conn conn, List topics) {
            this.conn = conn;
            this.topics = topics;
        }

        @Override
        public void run() {
            String jaasTemplate = "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"%s\" password=\"%s\";";
            String jaasCfg = String.format(jaasTemplate, conn.username, conn.password);

            Properties props = new Properties();
            props.put("bootstrap.servers", conn.servers);
            props.put("group.id", conn.groupId);
            props.put("enable.auto.commit", "true");
            props.put("auto.commit.interval.ms", "1000");
            props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
            props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
            props.put("security.protocol", "SASL_PLAINTEXT");
            props.put("sasl.mechanism", "PLAIN");
            props.put("sasl.jaas.config", jaasCfg);
            try(KafkaConsumer consumer = new KafkaConsumer<>(props)) {
                consumer.subscribe(new ArrayList<>(topics));
                // fix sleeptime to avoid to busy cpu usage;
                long sleepTime = 1L;
                while (true) {
                    ConsumerRecords records = consumer.poll(Duration.ofMillis(sleepTime));
                    if(records.isEmpty()){
                        sleepTime = 1000L;
                    }else{
                        sleepTime = 1L;
                    }
                    for (ConsumerRecord record : records) {
                        String topic = record.topic();
                        if (listener != null) {
                            listener.handle(record.value(), topic);
                        }
                        MessageEvent event = executors.get(topic);
                        if (event == null) {
                            if (defaultExecutor != null) {
                                invoke(defaultExecutor.instance, defaultExecutor.method, record.value(), topic);
                            } else if (listener == null) {
                                LOG.warn("no `{}` event handler defined", topic);
                            }
                            continue;
                        }

                        invoke(event.instance, event.method, record.value());
                    }
                }
            }
        }

        private void invoke(Object instance, Method method, Object... param) {
            try {
                method.invoke(instance, param);
            } catch (IllegalAccessException | InvocationTargetException e) {
                // ignore error
                LOG.warn("Event process error, ", e);
            }
        }
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy