com.ctrip.infosec.rule.executor.RulesExecutorService.java Source code

Java tutorial

Introduction

Here is the source code for com.ctrip.infosec.rule.executor.RulesExecutorService.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.executor;

import static com.ctrip.infosec.configs.utils.EventBodyUtils.valueAsList;
import static com.ctrip.infosec.configs.utils.EventBodyUtils.valueAsMap;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.ctrip.infosec.common.Constants;
import com.ctrip.infosec.common.model.RiskFact;
import com.ctrip.infosec.configs.Configs;
import com.ctrip.infosec.configs.event.Rule;
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.BeanMapper;
import static com.ctrip.infosec.configs.utils.EventBodyUtils.valueAsInt;
import static com.ctrip.infosec.configs.utils.Utils.JSON;
import com.ctrip.infosec.rule.Contexts;
import com.ctrip.infosec.rule.engine.StatelessRuleEngine;
import com.ctrip.infosec.sars.util.GlobalConfig;
import com.ctrip.infosec.sars.util.SpringContextHolder;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 
 *
 * @author zhengby
 */
@Service
public class RulesExecutorService {

    private static final Logger logger = LoggerFactory.getLogger(RulesExecutorService.class);
    // 
    private int timeout = GlobalConfig.getInteger("Rules.executor.timeout", 10000);

    /**
     * ?
     */
    public RiskFact executeSyncRules(RiskFact fact) {

        if (fact.results == null) {
            fact.setResults(new HashMap<String, Map<String, Object>>());
        }
        if (fact.ext == null) {
            fact.setExt(new HashMap<String, Object>());
        }
        executeParallel(fact);
        buidFinalResult(fact, false);

        if (!Constants.eventPointsWithScene.contains(fact.eventPoint)) {
            TraceLogger.traceLog("??. finalResult: " + JSON.toJSONString(fact.finalResult));
        } else {
            TraceLogger.traceLog("??[?]. finalResultGroupByScene: "
                    + JSON.toJSONString(fact.finalResultGroupByScene));
        }
        return fact;
    }

    /**
     * 
     */
    public RiskFact executeAsyncRules(RiskFact fact) {

        if (fact.results == null) {
            fact.setResults(new HashMap<String, Map<String, Object>>());
        }
        if (fact.ext == null) {
            fact.setExt(new HashMap<String, Object>());
        }
        executeSerial(fact);
        buidFinalResult(fact, true);

        if (!Constants.eventPointsWithScene.contains(fact.eventPoint)) {
            TraceLogger.traceLog(
                    "?. finalResult: " + JSON.toJSONString(fact.finalResult4Async));
        } else {
            TraceLogger.traceLog("?[?]. finalResultGroupByScene: "
                    + JSON.toJSONString(fact.finalResultGroupByScene4Async));
        }
        return fact;
    }

    /**
     * ?
     */
    void buidFinalResult(RiskFact fact, boolean isAsync) {

        Map<String, Object> finalResult = Constants.defaultResult;
        Map<String, Object> finalResult4Async = Constants.defaultResult;
        if (!isAsync) {
            // finalResult
            for (Map<String, Object> rs : fact.results.values()) {
                finalResult = compareAndReturn(finalResult, rs);
            }
            fact.setFinalResult(Maps.newHashMap(finalResult));

            // originalRiskLevel
            int riskLevel = valueAsInt(finalResult, Constants.riskLevel);
            fact.finalResult.put(Constants.originalRiskLevel, riskLevel);

            fact.finalResult.remove(Constants.async);
            fact.finalResult.remove(Constants.timeUsage);
        } else {
            // finalResult4Async
            for (Map<String, Object> rs : fact.results4Async.values()) {
                finalResult4Async = compareAndReturn(finalResult4Async, rs);
            }
            fact.setFinalResult4Async(Maps.newHashMap(finalResult4Async));
            fact.finalResult4Async.remove(Constants.async);
            fact.finalResult4Async.remove(Constants.timeUsage);
        }

        // ?????
        if (!fact.finalWhitelistResult.isEmpty() && !isAsync) {
            // 0 : ???
            // 95?95???
            // 97??195????97
            int whitelistRiskLevel = valueAsInt(fact.finalWhitelistResult, Constants.riskLevel);
            if (whitelistRiskLevel == 0) {
                fact.setFinalResult(Maps.newHashMap(Constants.defaultResult));
            } else if (whitelistRiskLevel == 95) {
                fact.setFinalResult(Maps.newHashMap(fact.finalWhitelistResult));
            } else if (whitelistRiskLevel == 97) {
                int riskLevel = valueAsInt(finalResult, Constants.riskLevel);
                if (riskLevel < 195) {
                    fact.setFinalResult(Maps.newHashMap(fact.finalWhitelistResult));
                }
            }
        }
        fact.finalResult.remove(Constants.async);
        fact.finalResult.remove(Constants.timeUsage);

        // finalResultGroupByScene
        Map<String, Map<String, Object>> finalResultGroupByScene = isAsync ? fact.finalResultGroupByScene4Async
                : fact.finalResultGroupByScene;
        Map<String, Map<String, Object>> resultsGroupByScene = isAsync ? fact.resultsGroupByScene4Async
                : fact.resultsGroupByScene;
        for (Map<String, Object> rs : resultsGroupByScene.values()) {
            List<String> sceneTypeList = valueAsList(rs, Constants.riskScene);
            if (sceneTypeList != null) {
                for (String sceneType : sceneTypeList) {
                    int riskLevel = MapUtils.getInteger(rs, Constants.riskLevel, 0);
                    String riskMessage = MapUtils.getString(rs, Constants.riskMessage, "");

                    // finalResultGroupBySceneput 
                    Map<String, Object> sceneResult = finalResultGroupByScene.get(sceneType);
                    if (null == sceneResult) {
                        sceneResult = new HashMap<>();
                        sceneResult.put(Constants.riskLevel, riskLevel);
                        sceneResult.put(Constants.riskMessage, riskMessage);
                        finalResultGroupByScene.put(sceneType, sceneResult);
                    } else {
                        int lastRiskLevel = MapUtils.getInteger(sceneResult, Constants.riskLevel, 0);
                        if (riskLevel > lastRiskLevel) {
                            sceneResult.put(Constants.riskLevel, riskLevel);
                            sceneResult.put(Constants.riskMessage, riskMessage);
                        }
                    }
                }
            }
            Map<String, Map<String, Map<String, String>>> subLevelGroupBySceneType = valueAsMap(rs,
                    Constants.subSceneType);
            if (subLevelGroupBySceneType != null) {
                for (String sceneType : subLevelGroupBySceneType.keySet()) {
                    Map<String, Map<String, String>> subLevelGroupBySubSceneType = subLevelGroupBySceneType
                            .get(sceneType);

                    //?
                    Map<String, Object> sceneResult = finalResultGroupByScene.get(sceneType);
                    if (null == sceneResult) {
                        sceneResult = new HashMap<>();
                        sceneResult.put(Constants.riskLevel, 0);
                        sceneResult.put(Constants.riskMessage, "PASS");
                        finalResultGroupByScene.put(sceneType, sceneResult);
                    }

                    int sceneRiskLevel = valueAsInt(sceneResult, Constants.riskLevel);
                    Map<String, Map<String, String>> finalSubResults = Maps.newHashMap();

                    for (Entry<String, Map<String, String>> entry : subLevelGroupBySubSceneType.entrySet()) {

                        // ????
                        int subSceneRiskLevel = valueAsInt(entry.getValue(), Constants.riskLevel);
                        if (subSceneRiskLevel > sceneRiskLevel) {
                            finalSubResults.put(entry.getKey(), entry.getValue());
                        }

                    }

                    sceneResult.put(Constants.subSceneType, finalSubResults);
                }
            }
        }
        if (!isAsync) {
            fact.setFinalResultGroupByScene(Maps.newHashMap(finalResultGroupByScene));
            fact.finalResultGroupByScene.remove(Constants.async);
            fact.finalResultGroupByScene.remove(Constants.timeUsage);
        } else {
            fact.setFinalResultGroupByScene4Async(Maps.newHashMap(finalResultGroupByScene));
            fact.finalResultGroupByScene4Async.remove(Constants.async);
            fact.finalResultGroupByScene4Async.remove(Constants.timeUsage);
        }
    }

    /**
     * 
     */
    void executeSerial(RiskFact fact) {

        // matchRules      
        List<Rule> matchedRules = Configs.matchRules(fact, true);
        TraceLogger.traceLog("? " + matchedRules.size() + " ? ...");
        StatelessRuleEngine statelessRuleEngine = SpringContextHolder.getBean(StatelessRuleEngine.class);

        StopWatch clock = new StopWatch();
        for (Rule rule : matchedRules) {
            String packageName = rule.getRuleNo();
            RuleMonitorHelper.newTrans(fact, RuleMonitorType.RULE, packageName);
            TraceLogger.beginNestedTrans(fact.eventId);
            TraceLogger.setNestedLogPrefix("[" + packageName + "]");
            Contexts.setPolicyOrRuleNo(packageName);
            try {
                clock.reset();
                clock.start();

                // set default result
                if (!Constants.eventPointsWithScene.contains(fact.eventPoint)) {
                    Map<String, Object> defaultResult = Maps.newHashMap();
                    defaultResult.put(Constants.riskLevel, 0);
                    defaultResult.put(Constants.riskMessage, "PASS");
                    fact.results4Async.put(rule.getRuleNo(), defaultResult);
                }

                // add current execute ruleNo and logPrefix before execution
                fact.ext.put(Constants.key_ruleNo, rule.getRuleNo());
                fact.ext.put(Constants.key_isAsync, true);

                statelessRuleEngine.execute(packageName, fact);

                // remove current execute ruleNo when finished execution.
                fact.ext.remove(Constants.key_ruleNo);
                fact.ext.remove(Constants.key_isAsync);

                clock.stop();
                long handlingTime = clock.getTime();

                if (!Constants.eventPointsWithScene.contains(fact.eventPoint)) {

                    Map<String, Object> resultWithScene = fact.resultsGroupByScene4Async.get(packageName);
                    if (resultWithScene != null) {
                        resultWithScene.put(Constants.async, false);
                        resultWithScene.put(Constants.timeUsage, handlingTime);

                        TraceLogger.traceLog(">>>> [" + packageName
                                + "] : [???] riskLevel = "
                                + resultWithScene.get(Constants.riskLevel) + ", riskMessage = "
                                + resultWithScene.get(Constants.riskMessage) + ", riskScene = "
                                + resultWithScene.get(Constants.riskScene) + ", usage = "
                                + resultWithScene.get(Constants.timeUsage) + "ms");
                    }

                    Map<String, Object> result = fact.results4Async.get(packageName);
                    if (result != null) {
                        result.put(Constants.async, true);
                        result.put(Constants.timeUsage, handlingTime);

                        TraceLogger.traceLog(">>>> [" + packageName + "] : riskLevel = "
                                + result.get(Constants.riskLevel) + ", riskMessage = "
                                + result.get(Constants.riskMessage) + ", usage = " + result.get(Constants.timeUsage)
                                + "ms");
                    }

                } else {

                    Map<String, Object> result = fact.results4Async.get(packageName);
                    if (result != null) {
                        result.put(Constants.async, false);
                        result.put(Constants.timeUsage, handlingTime);
                        int riskLevel = MapUtils.getIntValue(result, Constants.riskLevel, 0);
                        if (riskLevel > 0) {
                            TraceLogger.traceLog(">>>> [" + packageName
                                    + "] : [?] riskLevel = "
                                    + result.get(Constants.riskLevel) + ", riskMessage = "
                                    + result.get(Constants.riskMessage) + ", usage = "
                                    + result.get(Constants.timeUsage) + "ms");
                        }
                    }

                    Map<String, Object> resultWithScene = fact.resultsGroupByScene4Async.get(packageName);
                    if (resultWithScene != null) {
                        resultWithScene.put(Constants.async, true);
                        resultWithScene.put(Constants.timeUsage, handlingTime);

                        TraceLogger.traceLog(">>>> [" + packageName + "] [?]: riskLevel = "
                                + resultWithScene.get(Constants.riskLevel) + ", riskMessage = "
                                + resultWithScene.get(Constants.riskMessage) + ", riskScene = "
                                + resultWithScene.get(Constants.riskScene) + ", usage = "
                                + resultWithScene.get(Constants.timeUsage) + "ms");
                    } else {
                        TraceLogger.traceLog(
                                ">>>> [" + packageName + "] [?]: ?");
                    }
                }

            } catch (Throwable ex) {
                logger.warn(Contexts.getLogPrefix() + ". packageName: " + packageName, ex);
                TraceLogger.traceLog("[" + rule.getRuleNo() + "] EXCEPTION: " + ex.toString());
            } finally {
                TraceLogger.commitNestedTrans();
                RuleMonitorHelper.commitTrans(fact);
                Contexts.clearLogPrefix();
            }
        }
    }

    /**
     * 
     */
    void executeParallel(RiskFact fact) {

        // matchRules        
        List<Rule> matchedRules = Configs.matchRules(fact, false);

        TraceLogger.traceLog("? " + matchedRules.size() + " ? ...");
        List<Callable<RuleExecuteResultWithEvent>> runs = Lists.newArrayList();
        for (Rule rule : matchedRules) {
            final RiskFact factCopy = BeanMapper.copy(fact, RiskFact.class);

            // set default result
            if (!Constants.eventPointsWithScene.contains(factCopy.eventPoint)) {
                Map<String, Object> defaultResult = Maps.newHashMap();
                defaultResult.put(Constants.riskLevel, 0);
                defaultResult.put(Constants.riskMessage, "PASS");
                factCopy.results.put(rule.getRuleNo(), defaultResult);
            }

            final StatelessRuleEngine statelessRuleEngine = SpringContextHolder.getBean(StatelessRuleEngine.class);
            final String packageName = rule.getRuleNo();
            final String _logPrefix = Contexts.getLogPrefix();
            final String _traceLoggerParentTransId = TraceLogger.getTransId();

            try {
                // add current execute ruleNo before execution
                factCopy.ext.put(Constants.key_ruleNo, rule.getRuleNo());
                factCopy.ext.put(Constants.key_isAsync, false);

                runs.add(new Callable<RuleExecuteResultWithEvent>() {

                    @Override
                    public RuleExecuteResultWithEvent call() throws Exception {
                        RuleMonitorHelper.newTrans(factCopy, RuleMonitorType.RULE, packageName);
                        TraceLogger.beginTrans(factCopy.eventId);
                        TraceLogger.setParentTransId(_traceLoggerParentTransId);
                        TraceLogger.setLogPrefix("[" + packageName + "]");
                        Contexts.setPolicyOrRuleNo(packageName);
                        try {
                            long start = System.currentTimeMillis();
                            // remove current execute ruleNo when finished execution.
                            statelessRuleEngine.execute(packageName, factCopy);

                            long handlingTime = System.currentTimeMillis() - start;

                            if (!Constants.eventPointsWithScene.contains(factCopy.eventPoint)) {

                                Map<String, Object> resultWithScene = factCopy.resultsGroupByScene.get(packageName);
                                if (resultWithScene != null) {
                                    resultWithScene.put(Constants.async, false);
                                    resultWithScene.put(Constants.timeUsage, handlingTime);

                                    TraceLogger.traceLog(">>>> [" + packageName
                                            + "] : [???] riskLevel = "
                                            + resultWithScene.get(Constants.riskLevel) + ", riskMessage = "
                                            + resultWithScene.get(Constants.riskMessage) + ", riskScene = "
                                            + resultWithScene.get(Constants.riskScene) + ", usage = "
                                            + resultWithScene.get(Constants.timeUsage) + "ms");
                                }

                                Map<String, Object> result = factCopy.results.get(packageName);
                                if (result != null) {
                                    result.put(Constants.async, false);
                                    result.put(Constants.timeUsage, handlingTime);

                                    TraceLogger.traceLog(">>>> [" + packageName + "] : riskLevel = "
                                            + result.get(Constants.riskLevel) + ", riskMessage = "
                                            + result.get(Constants.riskMessage) + ", usage = "
                                            + result.get(Constants.timeUsage) + "ms");
                                }

                            } else {

                                Map<String, Object> result = factCopy.results.get(packageName);
                                if (result != null) {
                                    result.put(Constants.async, false);
                                    result.put(Constants.timeUsage, handlingTime);
                                    int riskLevel = MapUtils.getIntValue(result, Constants.riskLevel, 0);
                                    if (riskLevel > 0) {
                                        TraceLogger.traceLog(">>>> [" + packageName
                                                + "] [?]: [??] riskLevel = "
                                                + result.get(Constants.riskLevel) + ", riskMessage = "
                                                + result.get(Constants.riskMessage) + ", usage = "
                                                + result.get(Constants.timeUsage) + "ms");
                                    }
                                }

                                Map<String, Object> resultWithScene = factCopy.resultsGroupByScene.get(packageName);
                                if (resultWithScene != null) {
                                    resultWithScene.put(Constants.async, false);
                                    resultWithScene.put(Constants.timeUsage, handlingTime);

                                    TraceLogger.traceLog(
                                            ">>>> [" + packageName + "] [?]: riskLevel = "
                                                    + resultWithScene.get(Constants.riskLevel) + ", riskMessage = "
                                                    + resultWithScene.get(Constants.riskMessage) + ", riskScene = "
                                                    + resultWithScene.get(Constants.riskScene) + ", usage = "
                                                    + resultWithScene.get(Constants.timeUsage) + "ms");
                                } else {
                                    TraceLogger.traceLog(">>>> [" + packageName
                                            + "] [?]: ?");
                                }
                            }
                            return new RuleExecuteResultWithEvent(packageName, factCopy.results,
                                    factCopy.resultsGroupByScene, factCopy.eventBody, factCopy.ext);
                        } catch (Exception e) {
                            logger.warn(_logPrefix + ". packageName: " + packageName, e);
                        } finally {
                            TraceLogger.commitTrans();
                            RuleMonitorHelper.commitTrans2Trunk(factCopy);
                            Contexts.clearLogPrefix();
                        }
                        return null;
                    }

                });

            } catch (Throwable ex) {
                logger.warn(_logPrefix + ". packageName: " + packageName, ex);
            }

        }
        List<RuleExecuteResultWithEvent> rawResult = new ArrayList<RuleExecuteResultWithEvent>();
        try {
            List<Future<RuleExecuteResultWithEvent>> results = ParallelExecutorHolder.excutor.invokeAll(runs,
                    timeout, TimeUnit.MILLISECONDS);
            for (Future f : results) {
                try {
                    if (f.isDone()) {
                        RuleExecuteResultWithEvent r = (RuleExecuteResultWithEvent) f.get();
                        rawResult.add(r);
                    } else {
                        f.cancel(true);
                    }
                } catch (Exception e) {
                    // ignored
                }
            }
        } catch (Exception e) {
            // ignored
        }
        if (rawResult.size() > 0) {
            for (RuleExecuteResultWithEvent item : rawResult) {
                // merge eventBody
                if (item.getEventBody() != null) {
                    for (String key : item.getEventBody().keySet()) {
                        Object value = item.getEventBody().get(key);
                        if (!fact.eventBody.containsKey(key) && value != null) {
                            fact.eventBody.put(key, value);
                        }
                    }
                }
                // merge ext
                if (item.getExt() != null) {
                    for (String key : item.getExt().keySet()) {
                        Object value = item.getExt().get(key);
                        if (!fact.ext.containsKey(key) && value != null) {
                            fact.ext.put(key, value);
                        }
                    }
                }
                // merge results
                if (item.getResults() != null) {
                    fact.results.putAll(item.getResults());
                }
                // merge resultsGroupByScene
                if (item.getResultsGroupByScene() != null) {
                    fact.resultsGroupByScene.putAll(item.getResultsGroupByScene());
                }
            }
        }
    }

    class RuleExecuteResultWithEvent {

        private String ruleNo;
        private Map<String, Map<String, Object>> results;
        private Map<String, Map<String, Object>> resultsGroupByScene;
        private Map<String, Object> eventBody;
        private Map<String, Object> ext;

        public RuleExecuteResultWithEvent(String ruleNo, Map<String, Map<String, Object>> results,
                Map<String, Map<String, Object>> resultsGroupByScene, Map<String, Object> eventBody,
                Map<String, Object> ext) {
            this.ruleNo = ruleNo;
            this.results = results;
            this.resultsGroupByScene = resultsGroupByScene;
            this.eventBody = eventBody;
            this.ext = ext;
        }

        public String getRuleNo() {
            return ruleNo;
        }

        public void setRuleNo(String ruleNo) {
            this.ruleNo = ruleNo;
        }

        public Map<String, Map<String, Object>> getResults() {
            return results;
        }

        public void setResults(Map<String, Map<String, Object>> results) {
            this.results = results;
        }

        public Map<String, Map<String, Object>> getResultsGroupByScene() {
            return resultsGroupByScene;
        }

        public void setResultsGroupByScene(Map<String, Map<String, Object>> resultsGroupByScene) {
            this.resultsGroupByScene = resultsGroupByScene;
        }

        public Map<String, Object> getEventBody() {
            return eventBody;
        }

        public void setEventBody(Map<String, Object> eventBody) {
            this.eventBody = eventBody;
        }

        public Map<String, Object> getExt() {
            return ext;
        }

        public void setExt(Map<String, Object> ext) {
            this.ext = ext;
        }

    }

    /**
     * finalResult
     */
    Map<String, Object> compareAndReturn(Map<String, Object> oldResult, Map<String, Object> newResult) {
        if (newResult == null) {
            return oldResult;
        }
        if (oldResult == null) {
            return newResult;
        }
        int newRriskLevel = MapUtils.getInteger(newResult, Constants.riskLevel, 0);
        int oldRriskLevel = MapUtils.getInteger(oldResult, Constants.riskLevel, 0);
        if (newRriskLevel > oldRriskLevel) {
            return newResult;
        }
        return oldResult;
    }
}