com.ctrip.infosec.rule.rabbitmq.RabbitMqMessageHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.ctrip.infosec.rule.rabbitmq.RabbitMqMessageHandler.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ctrip.infosec.rule.rabbitmq;

import com.ctrip.infosec.common.Constants;
import com.ctrip.infosec.common.model.RiskFact;
import com.ctrip.infosec.common.model.RiskResult;
import com.ctrip.infosec.configs.event.*;
import com.ctrip.infosec.configs.event.enums.PersistColumnSourceType;
import com.ctrip.infosec.configs.rule.monitor.RuleMonitorRepository;
import com.ctrip.infosec.configs.rule.trace.logger.TraceLogger;
import com.ctrip.infosec.configs.rulemonitor.RuleMonitorHelper;
import com.ctrip.infosec.configs.rulemonitor.RuleMonitorType;
import com.ctrip.infosec.configs.utils.EventBodyUtils;
import com.ctrip.infosec.configs.utils.Utils;
import com.ctrip.infosec.rule.Contexts;
import com.ctrip.infosec.rule.convert.RiskFactPersistStrategy;
import com.ctrip.infosec.rule.convert.internal.InternalRiskFact;
import com.ctrip.infosec.rule.convert.offline4j.RiskEventConvertor;
import com.ctrip.infosec.rule.convert.persist.*;
import com.ctrip.infosec.rule.executor.*;
import com.ctrip.infosec.rule.utils.ValueExtractUtils;
import com.ctrip.infosec.sars.monitor.SarsMonitorContext;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.meidusa.fastjson.JSON;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import static com.ctrip.infosec.common.SarsMonitorWrapper.*;
import static com.ctrip.infosec.configs.utils.EventBodyUtils.valueAsString;

/**
 * @author zhengby
 */
public class RabbitMqMessageHandler {

    private static Logger logger = LoggerFactory.getLogger(RabbitMqMessageHandler.class);

    @Autowired
    private RulesExecutorService rulesExecutorService;
    @Autowired
    private PreRulesExecutorService preRulesExecutorService;
    @Autowired
    private PostRulesExecutorService postRulesExecutorService;
    @Autowired
    private ModelRulesExecutorService modelRulesExecutorService;
    @Autowired
    private DispatcherMessageSender dispatcherMessageSender;
    @Autowired
    private CallbackMessageSender callbackMessageSender;
    @Autowired
    private EventDataMergeService eventDataMergeService;
    @Autowired
    private OfflineMessageSender offlineMessageSender;
    @Autowired
    private CounterPushRulesExecutorService counterPushRuleExrcutorService;
    @Autowired
    private RiskEventConvertor riskEventConvertor;
    @Autowired
    private Offline4jService offline4jService;

    public void handleMessage(Object message) throws Exception {
        RiskFact fact = null;
        String factTxt;
        InternalRiskFact internalRiskFact = null;
        try {

            if (message instanceof byte[]) {
                factTxt = new String((byte[]) message, Constants.defaultCharset);
            } else if (message instanceof String) {
                factTxt = (String) message;
            } else {
                throw new IllegalArgumentException("????\"String\"\"byte[]\"");
            }

            logger.info("MQ: fact=" + factTxt);
            fact = JSON.parseObject((String) factTxt, RiskFact.class);
            Contexts.setAsync(true);
            Contexts.setLogPrefix("[" + fact.eventPoint + "][" + fact.eventId + "] ");
            SarsMonitorContext.setLogPrefix(Contexts.getLogPrefix());

            boolean traceLoggerEnabled = MapUtils.getBoolean(fact.ext, Constants.key_traceLogger, true);
            TraceLogger.enabled(traceLoggerEnabled);

            RuleMonitorHelper.newTrans(fact, RuleMonitorType.CP_ASYNC);

            // ??
            // S0 - ??
            // S1 - ?
            // S2 - ??
            // S3 - 
            // ??GET
            try {
                RuleMonitorHelper.newTrans(fact, RuleMonitorType.GET);
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[??]");
                eventDataMergeService.executeRedisGet(fact);
            } finally {
                TraceLogger.commitTrans();
                RuleMonitorHelper.commitTrans(fact);
            }
            // ?            
            try {
                RuleMonitorHelper.newTrans(fact, RuleMonitorType.PRE_RULE_WRAP);
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[?]");
                preRulesExecutorService.executePreRules(fact, true);
            } finally {
                TraceLogger.commitTrans();
                RuleMonitorHelper.commitTrans(fact);
            }
            // 
            try {
                RuleMonitorHelper.newTrans(fact, RuleMonitorType.RULE_WRAP);
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[]");
                rulesExecutorService.executeAsyncRules(fact);
            } finally {
                TraceLogger.commitTrans();
                RuleMonitorHelper.commitTrans(fact);
            }
            // 
            try {
                RuleMonitorHelper.newTrans(fact, RuleMonitorType.MODEL_RULE_WRAP);
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[]");
                modelRulesExecutorService.executeModelRules(fact);
            } finally {
                TraceLogger.commitTrans();
                RuleMonitorHelper.commitTrans(fact);
            }
            // ??
            try {
                RuleMonitorHelper.newTrans(fact, RuleMonitorType.POST_RULE_WRAP);
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[??]");
                postRulesExecutorService.executePostRules(fact, true);
            } finally {
                TraceLogger.commitTrans();
                RuleMonitorHelper.commitTrans(fact);
            }
            // ??PUT
            try {
                RuleMonitorHelper.newTrans(fact, RuleMonitorType.PUT);
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[??]");
                eventDataMergeService.executeRedisPut(fact);
            } finally {
                TraceLogger.commitTrans();
                RuleMonitorHelper.commitTrans(fact);
            }
            //Counter??
            try {
                RuleMonitorHelper.newTrans(fact, RuleMonitorType.PUSH_WRAP);
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[Counter?]");
                counterPushRuleExrcutorService.executeCounterPushRules(fact, true);
            } finally {
                TraceLogger.commitTrans();
                RuleMonitorHelper.commitTrans(fact);
            }

            RuleMonitorHelper.commitTrans(fact);

            // -------------------------------- ? -------------------------------------- //
            beforeInvoke("CardRiskDB.CheckResultLog.saveRuleResult");
            Long riskReqId = MapUtils.getLong(fact.ext, Constants.key_reqId);
            boolean outerReqId = riskReqId != null;
            internalRiskFact = offline4jService.saveForOffline(fact);
            if (internalRiskFact != null && internalRiskFact.getReqId() > 0) {
                riskReqId = internalRiskFact.getReqId();
            }

            // ?
            beforeInvoke("CardRiskDB.CheckResultLog.saveRuleResult");
            try {
                TraceLogger.beginTrans(fact.eventId, "S3");
                TraceLogger.setLogPrefix("[?CheckResultLog]");
                if (riskReqId != null && riskReqId > 0) {
                    TraceLogger.traceLog("reqId = " + riskReqId);
                    saveRuleResult(riskReqId, fact, fact.whitelistResults, outerReqId);
                    saveRuleResult(riskReqId, fact, fact.results, outerReqId);
                    saveRuleResult(riskReqId, fact, fact.results4Async, outerReqId);
                    saveRuleResult(riskReqId, fact, fact.resultsGroupByScene, outerReqId);
                    saveRuleResult(riskReqId, fact, fact.resultsGroupByScene4Async, outerReqId);
                }
            } catch (Exception ex) {
                fault("CardRiskDB.CheckResultLog.saveRuleResult");
                logger.error(
                        Contexts.getLogPrefix()
                                + "?[InfoSecurity_CheckResultLog]?.",
                        ex);
            } finally {
                long usage = afterInvoke("CardRiskDB.CheckResultLog.saveRuleResult");
                TraceLogger.traceLog(": " + usage + "ms");
                TraceLogger.commitTrans();
            }

        } catch (Throwable ex) {
            logger.error(Contexts.getLogPrefix() + "invoke handleMessage exception.", ex);
        } finally {
            if (fact != null) {
                // ??DataDispatcher
                try {
                    beforeInvoke("DataDispatcher.sendMessage");
                    dispatcherMessageSender.sendToDataDispatcher(fact);
                } catch (Exception ex) {
                    fault("DataDispatcher.sendMessage");
                    logger.error(Contexts.getLogPrefix() + "send dispatcher message fault.", ex);
                } finally {
                    afterInvoke("DataDispatcher.sendMessage");
                }

                int riskLevel = MapUtils.getInteger(fact.finalResult, Constants.riskLevel, 0);
                if (riskLevel > 0) {
                    // ??Offline4J
                    if (internalRiskFact != null
                            && MapUtils.getBoolean(fact.ext, Offline4jService.PUSH_OFFLINE_WORK_ORDER_KEY, false)) {
                        beforeInvoke("Offline.sendMessage");
                        try {
                            Object eventObj = riskEventConvertor.convert(internalRiskFact, riskLevel,
                                    HeaderMappingBizType.Offline4J);
                            offlineMessageSender.sendToOffline(eventObj);
                        } catch (Exception ex) {
                            fault("Offline.sendMessage");
                            logger.error(Contexts.getLogPrefix() + "send Offline4J message fault.", ex);
                        } finally {
                            afterInvoke("Offline.sendMessage");
                        }
                    }
                }

                try {

                    //??factresults0?
                    boolean withScene = Constants.eventPointsWithScene.contains(fact.eventPoint);
                    if (!withScene) {
                        //?
                        for (Entry<String, Map<String, Object>> entry : fact.results.entrySet()) {
                            String ruleNo = entry.getKey();
                            int rLevel = NumberUtils
                                    .toInt(MapUtils.getString(entry.getValue(), Constants.riskLevel));
                            if (rLevel > 0) {
                                //??
                                String distinct = getDistinctValue(fact, ruleNo);
                                RuleMonitorRepository.increaseCounter(fact.getEventPoint(), ruleNo, distinct);
                            }
                        }
                        for (Entry<String, Map<String, Object>> entry : fact.results4Async.entrySet()) {
                            String ruleNo = entry.getKey();
                            int rLevel = NumberUtils
                                    .toInt(MapUtils.getString(entry.getValue(), Constants.riskLevel));
                            if (rLevel > 0) {
                                //??
                                String distinct = getDistinctValue(fact, ruleNo);
                                RuleMonitorRepository.increaseCounter(fact.getEventPoint(), ruleNo, distinct);
                            }
                        }
                    } else {
                        //
                        for (Entry<String, Map<String, Object>> entry : fact.resultsGroupByScene.entrySet()) {
                            String ruleNo = entry.getKey();
                            int rLevel = NumberUtils
                                    .toInt(MapUtils.getString(entry.getValue(), Constants.riskLevel));
                            if (rLevel > 0) {
                                //                                RuleMonitorRepository.increaseCounter(fact.getEventPoint(), ruleNo);
                                //??
                                String distinct = getDistinctValue(fact, ruleNo);
                                RuleMonitorRepository.increaseCounter(fact.getEventPoint(), ruleNo, distinct);
                            }
                        }
                        for (Entry<String, Map<String, Object>> entry : fact.resultsGroupByScene4Async.entrySet()) {
                            String ruleNo = entry.getKey();
                            int rLevel = NumberUtils
                                    .toInt(MapUtils.getString(entry.getValue(), Constants.riskLevel));
                            if (rLevel > 0) {
                                //                                RuleMonitorRepository.increaseCounter(fact.getEventPoint(), ruleNo);
                                //??
                                String distinct = getDistinctValue(fact, ruleNo);
                                RuleMonitorRepository.increaseCounter(fact.getEventPoint(), ruleNo, distinct);
                            }
                        }
                    }

                } catch (Exception ex) {
                    logger.error(Contexts.getLogPrefix() + "RuleMonitorRepository increaseCounter fault.", ex);
                }

            }
        }
    }

    //??
    private final List<String> distinctFields = Lists.newArrayList("orderID", "OrderID", "orderId");

    /**
     * ??
     *
     * @param fact
     * @param ruleNo
     * @return
     */
    private String getDistinctValue(RiskFact fact, String ruleNo) {

        String distinctValue = null;

        for (String distinctField : distinctFields) {

            distinctValue = EventBodyUtils.valueAsString(fact.eventBody, distinctField);
            if (StringUtils.isNotBlank(distinctValue)) {
                //????
                break;
            }
        }

        return distinctValue;
    }

    private void saveRuleResult(Long riskReqId, RiskFact fact, Map<String, Map<String, Object>> results,
            boolean outerReqId) throws DbExecuteException {
        String eventPoint = fact.eventPoint;
        Long orderId = ValueExtractUtils.extractLongIgnoreCase(fact.eventBody, "orderId");
        Integer orderType = ValueExtractUtils.extractIntegerIgnoreCase(fact.eventBody, "orderType");
        Integer subOrderType = ValueExtractUtils.extractIntegerIgnoreCase(fact.eventBody, "subOrderType");
        RdbmsInsert insert = new RdbmsInsert();
        DistributionChannel channel = new DistributionChannel();
        channel.setChannelNo(RiskFactPersistStrategy.allInOne4ReqId);
        channel.setDatabaseType(DatabaseType.AllInOne_SqlServer);
        channel.setChannelDesc(RiskFactPersistStrategy.allInOne4ReqId);
        channel.setDatabaseURL(RiskFactPersistStrategy.allInOne4ReqId);
        insert.setChannel(channel);

        /**
         * [LogID] =  [ReqID] [RuleType] [RuleID] = 0 [RuleName] [RiskLevel]
         * [RuleRemark] [CreateDate] = now [DataChange_LastTime] = now
         * [IsHighlight] = 1
         */
        if (MapUtils.isNotEmpty(results)) {
            for (Entry<String, Map<String, Object>> entry : results.entrySet()) {
                try {
                    Long riskLevel = MapUtils.getLong(entry.getValue(), Constants.riskLevel);
                    if (riskLevel > 0) {
                        String ruleType = (String) entry.getValue().get(Constants.ruleType);//withScene ? (isAsync ? "SA" : "S") : (isAsync ? "NA" : "N");
                        TraceLogger.traceLog(
                                "[" + entry.getKey() + "] riskLevel = " + riskLevel + ", ruleType = " + ruleType);
                        insert.setTable("RiskControl_CheckResultLog");
                        insert.setColumnPropertiesMap(prepareRiskControlCheckResultLog(riskReqId, ruleType, entry,
                                riskLevel, eventPoint, orderId, orderType, subOrderType));
                        execute(insert);
                        if ("B".equals(ruleType) || "N".equals(ruleType)) {
                            insert.setTable("InfoSecurity_CheckResultLog");
                            insert.setColumnPropertiesMap(
                                    prepareInfoSecurityCheckResultLog(riskReqId, ruleType, entry, riskLevel));
                            execute(insert);
                        }
                    }
                } catch (Exception e) {
                    logger.error(Contexts.getLogPrefix() + "save InfoSecurity_CheckResultLog failed. reqId="
                            + riskReqId + ", result=" + entry, e);
                }
            }
        }
    }

    private void execute(DbOperation operation) throws DbExecuteException {
        PersistContext ctx = new PersistContext();
        operation.execute(ctx);
    }

    private Map<String, PersistColumnProperties> prepareRiskControlCheckResultLog(Long riskReqId, String ruleType,
            Entry<String, Map<String, Object>> entry, Long riskLevel, String eventPoint, Long orderId,
            Integer orderType, Integer subOrderType) {
        Map<String, PersistColumnProperties> map = Maps.newHashMap();
        PersistColumnProperties props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DB_PK);
        props.setColumnType(DataUnitColumnType.Long);
        map.put("LogID", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Long);
        props.setValue(riskReqId);
        map.put("RID", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.String);
        props.setValue(ruleType);
        map.put("RuleType", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Int);
        props.setValue(MapUtils.getInteger(entry.getValue(), Constants.ruleId, 0));
        map.put("RuleID", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.String);
        if ("B".equals(valueAsString(entry.getValue(), Constants.ruleType))) {
            props.setValue(valueAsString(entry.getValue(), Constants.ruleName));
        } else {
            props.setValue(entry.getKey());
        }
        map.put("RuleName", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Long);
        props.setValue(riskLevel);
        map.put("RiskLevel", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.String);
        props.setValue(MapUtils.getString(entry.getValue(), Constants.riskMessage));
        map.put("RuleRemark", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.CUSTOMIZE);
        props.setColumnType(DataUnitColumnType.Data);
        props.setExpression("const:now:date");
        map.put("DataChange_LastTime", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.String);
        props.setValue(eventPoint);
        map.put("EventPoint", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Long);
        props.setValue(orderId);
        map.put("OrderId", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Int);
        props.setValue(orderType);
        map.put("OrderType", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Int);
        props.setValue(subOrderType);
        map.put("SubOrderType", props);
        return map;
    }

    private Map<String, PersistColumnProperties> prepareInfoSecurityCheckResultLog(Long riskReqId, String ruleType,
            Entry<String, Map<String, Object>> entry, Long riskLevel) {
        Map<String, PersistColumnProperties> map = Maps.newHashMap();
        PersistColumnProperties props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DB_PK);
        props.setColumnType(DataUnitColumnType.Long);
        map.put("LogID", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Long);
        props.setValue(riskReqId);
        map.put("ReqID", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.String);
        props.setValue(ruleType);
        map.put("RuleType", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Int);
        props.setValue(MapUtils.getInteger(entry.getValue(), Constants.ruleId, 0));
        map.put("RuleID", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.String);
        if ("B".equals(valueAsString(entry.getValue(), Constants.ruleType))) {
            props.setValue(valueAsString(entry.getValue(), Constants.ruleName));
        } else {
            props.setValue(entry.getKey());
        }
        map.put("RuleName", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Long);
        props.setValue(riskLevel);
        map.put("RiskLevel", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.String);
        props.setValue(MapUtils.getString(entry.getValue(), Constants.riskMessage));
        map.put("RuleRemark", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.CUSTOMIZE);
        props.setColumnType(DataUnitColumnType.Data);
        props.setExpression("const:now:date");
        map.put("CreateDate", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.CUSTOMIZE);
        props.setColumnType(DataUnitColumnType.Data);
        props.setExpression("const:now:date");
        map.put("DataChange_LastTime", props);

        props = new PersistColumnProperties();
        props.setPersistColumnSourceType(PersistColumnSourceType.DATA_UNIT);
        props.setColumnType(DataUnitColumnType.Int);
        props.setValue(0);
        map.put("IsHighlight", props);

        return map;
    }

    /**
     * Callback
     */
    RiskResult buildRiskResult(RiskFact fact, CallbackRule callbackRule) {
        RiskResult result = new RiskResult();
        result.setEventPoint(fact.eventPoint);
        result.setEventId(fact.eventId);
        result.getResults().putAll(fact.finalResult);

        // ?PD?
        Map<String, String> fieldMapping = callbackRule.getFieldMapping();
        if (fieldMapping != null && !fieldMapping.isEmpty()) {
            for (String fieldName : fieldMapping.keySet()) {
                String newFieldName = fieldMapping.get(fieldName);
                Object fieldValue = getNestedProperty(fact, fieldName);
                if (fieldValue != null) {
                    result.getResults().put(newFieldName, fieldValue);
                }
            }
        }
        //        result.getResults().put("orderId", fact.eventBody.get("orderID"));
        //        result.getResults().put("hotelId", fact.eventBody.get("hotelID"));

        result.setRequestTime(fact.requestTime);
        result.setRequestReceive(fact.requestReceive);
        result.setResponseTime(Utils.fastDateFormatInMicroSecond.format(new Date()));
        return result;
    }

    Object getNestedProperty(Object factOrEventBody, String columnExpression) {
        try {
            Object value = PropertyUtils.getNestedProperty(factOrEventBody, columnExpression);
            return value;
        } catch (Exception ex) {
            logger.info(Contexts.getLogPrefix() + "getNestedProperty fault. message: " + ex.getMessage());
        }
        return null;
    }
}