【仅供内部供应商使用,不提供对外解答和培训】

Page tree

【仅供内部供应商使用,不提供对外解答和培训】

Skip to end of metadata
Go to start of metadata

一、特殊名词介绍

二、背景、场景介绍

在定时调度的最后一步各种推送处理过程中,经常涉及到对各种公式的支持,其中有两种场景较为特殊

1.使用的表达式规则并非帆软支持的特定表达式,而是具体的业务单独约定的。

2.使用了报表的跨sheet取数比如 report0~A1、block0~A1之类的

直接使用OutputFormulaProvider接口目前是无法支持的。

而OutputFormulaExtractorProvider接口就是为了让产品能够识别和转换特殊表达式而增加的公式提取处理的接口。

注:该接口在绝大多数场景下不会独立使用,文档仅做覆盖说明,以便开发者未来在阅读相关插件的源码时能知道这个接口是在做什么!

三、接口介绍

OutputFormulaExtractorProvider.java
package com.fr.schedule.extension.report.job.output.formula.extract;

import com.fr.schedule.base.bean.output.BaseOutputAction;
import com.fr.stable.fun.mark.Mutable;

import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author Cloud.Liu
 * @version 10.0
 * Created by Cloud.Liu on 2019/9/2
 */
public interface OutputFormulaExtractorProvider<T extends BaseOutputAction> extends Mutable {

    String XML_TAG = "OutputFormulaExtractorProvider";

    int CURRENT_LEVEL = 1;

    /**
     * 该BaseOutputAction类名
     * @return BaseOutputAction类名
     */
    String getActionClassName();

    /**
     * 将BaseOutputAction中特定项含有的符合pattern的公式提取出来作为key,创建其Formula作为value添加到map中
     * @param t 具体BaseOutputAction
     * @param pattern 公式正则
     * @param map 参数map
     */
    void addFormulaToMap(T t, Pattern pattern, Map<String, Object> map);
}


四、支持版本

产品线

版本

支持情况

备注

FR10.0支持
BI5.1支持
BI5.1.2支持
BI5.1.3支持

五、插件注册

plugin.xml
<extra-decision>
        <OutputFormulaExtractorProvider class="your class name"/>
</extra-decision>


六、原理说明

ReportCalculationJob.java
package com.fr.schedule.extension.report.job.execute;

...

public abstract class ReportCalculationJob extends BaseCalculationJob {

    ...

    @Override
    public Pair<CalculationResult, List<String>> calculation() throws Exception {

        Reportlet reportlet = ReportHelper.generateReportlet(this.templatePath);
        List<String> attachFileList = new ArrayList<String>();
        if (recordList.isEmpty()) {
            throw new EmptyRecordListException("Empty record list, output action will not be executed");
        }
        for (Map<String, Object> parameterMap : this.recordList) {
            String sessionId = null;
            try {
                //定时调度任务也加一个session
                this.addUserParam(parameterMap);
                // 单独处理下定时调度中挂载的公式类型fr_locale参数
                DecisionTemplateUtils.preDealWithFRLocale(parameterMap);
                addFormulaToParameterMap(ScheduleParameterUtils.POLY_BLOCK_FORMULA_REGEX, parameterMap);
                String actorName = ScheduleTaskShowTypeFactory.fromInteger(this.getScheduleTask().getShowType()).getActorName();
                ReportSessionIDInfor sessionIDInfor = new ReportSessionIDInfor(parameterMap, this.templatePath, ActorFactory.getActor(actorName));
                sessionIDInfor.updateTableDataSource();
                sessionId = SessionPoolManager.addSessionIDInfor(sessionIDInfor);
                parameterMap.put(SessionInfo.SESSIONID.toString(), sessionId);
                TemplateWorkBook wbTpl = this.getTemplateWorkBook(reportlet, parameterMap);
                if (wbTpl == null) {
                    return new Pair<>(CalculationResult.ERROR, attachFileList);
                }
                CalculationResult calculationResult = calculateAndGenerateAttachment(parameterMap, wbTpl, attachFileList);
                if (CalculationResult.SUCCESS != calculationResult) {
                    return new Pair<>(calculationResult, attachFileList);
                }
            } finally {
                if (sessionId != null) {
                    SessionPoolManager.closeSession(sessionId);
                }
            }
        }
        return new Pair<>(CalculationResult.SUCCESS, attachFileList);
    }

    ...

    /**
     * 将附件名称、附件处理通知里regex匹配的公式及其对应Formula加入到parameterMap中,跟随报表计算
     * @param regex 公式匹配正则
     * @param parameterMap 参数Map
     */
    public void addFormulaToParameterMap(Pattern regex, Map<String, Object> parameterMap) {

        ScheduleOutput scheduleOutput = this.getScheduleTask().getScheduleOutput();

        //附件名称
        String fileName = scheduleOutput.getBaseName();
        ScheduleParameterUtils.addFormulaToMap(fileName, regex, parameterMap);

        //附件处理
        List<BaseOutputAction> actionList = scheduleOutput.getOutputActionList();
        for (BaseOutputAction action : actionList) {
            OutputFormulaExtractorProvider provider = OutputFormulaExtractBox.KEY.fromActionClassName(action.getActionName());
            if (provider != null) {
                provider.addFormulaToMap(action, regex, parameterMap);
            }
        }
    }

    ...
}

OutputFormulaExtractBox.java
package com.fr.schedule.extension.report.job.output.formula.extract;

import com.fr.decision.ExtraDecisionClassManager;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.manage.PluginFilter;
import com.fr.plugin.observer.PluginEventType;
import com.fr.schedule.extension.report.job.output.formula.extract.impl.EmailOutputFormulaExtractor;
import com.fr.schedule.extension.report.job.output.formula.extract.impl.MobileMsgOutputFormulaExtractor;
import com.fr.schedule.extension.report.job.output.formula.extract.impl.SmsOutputFormulaExtractor;
import com.fr.schedule.extension.report.job.output.formula.extract.impl.SystemMsgOutputFormulaExtractor;
import com.fr.stable.Filter;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Cloud.Liu
 * @version 10.0
 * Created by Cloud.Liu on 2019/9/2
 */
public class OutputFormulaExtractBox {

    public static final OutputFormulaExtractBox KEY = new OutputFormulaExtractBox();

    private Map<String, OutputFormulaExtractorProvider> map = new ConcurrentHashMap<>();

    private OutputFormulaExtractBox() {
        registerInternal();
        listenPlugin();
    }

    private void registerInternal() {
        register(new EmailOutputFormulaExtractor());
        register(new SystemMsgOutputFormulaExtractor());
        register(new MobileMsgOutputFormulaExtractor());
        register(new SmsOutputFormulaExtractor());
    }

    public void register(OutputFormulaExtractorProvider provider) {
        if (!map.containsKey(provider.getActionClassName())) {
            map.put(provider.getActionClassName(), provider);
        }
    }

    private void remove(OutputFormulaExtractorProvider provider) {
        if (provider != null) {
            map.remove(provider.getActionClassName());
        }
    }

    public OutputFormulaExtractorProvider fromActionClassName(String className) {
        return map.containsKey(className) ? map.get(className) : null;
    }

    private void listenPlugin() {

        Set<OutputFormulaExtractorProvider> providers = ExtraDecisionClassManager.getInstance().getArray(OutputFormulaExtractorProvider.XML_TAG);
        for (OutputFormulaExtractorProvider provider : providers) {
            register(provider);
        }
        Filter<PluginContext> filter = new PluginFilter() {

            @Override
            public boolean accept(PluginContext pluginContext) {

                return pluginContext.contain(OutputFormulaExtractorProvider.XML_TAG);
            }
        };
        EventDispatcher.listen(PluginEventType.AfterRun, new Listener<PluginContext>() {

            @Override
            public void on(Event event, PluginContext param) {

                Set<OutputFormulaExtractorProvider> set = param.getRuntime().get(OutputFormulaExtractorProvider.XML_TAG);
                for (OutputFormulaExtractorProvider provider : set) {
                    register(provider);
                }
            }
        }, filter);

        EventDispatcher.listen(PluginEventType.BeforeStop, new Listener<PluginContext>() {

            @Override
            public void on(Event event, PluginContext param) {

                Set<OutputFormulaExtractorProvider> set = param.getRuntime().get(OutputFormulaExtractorProvider.XML_TAG);
                for (OutputFormulaExtractorProvider provider : set) {
                    remove(provider);
                }
            }
        }, filter);
    }
}


七、特殊限制说明

从OutputFormulaExtractBox这个管理类中可以看出,OutputFormulaExtractorProvider接口仅仅只能对用户自行扩展或未注册公式提取接口的BaseOutputAction生效,产品本身的相关功能均已注册。具体可以参见

EmailOutputFormulaExtractor、SystemMsgOutputFormulaExtractor、MobileMsgOutputFormulaExtractor、SmsOutputFormulaExtractor。

addFormulaToMap接口方法的实现,一般也相对固定

ScheduleParameterUtils.addFormulaToMap(outputAction.getSubject(), pattern, map);
ScheduleParameterUtils.addFormulaToMap(outputAction.getBodyContent(), pattern, map);

【从开发者角度看,该接口未来可能是个技术债务!应该能不使用就不要使用。学习该接口,仅仅是为了未来在开发客户需求的过程中能够识别出客户环境中使用了什么样功能的接口,以便预估相关风险!】

八、常用链接

入门demo地址:demo-output-formula-extractor-provider

九、开源案例

免责声明:所有文档中的开源示例,均为开发者自行开发并提供。仅用于参考和学习使用,开发者和官方均无义务对开源案例所涉及的所有成果进行教学和指导。若作为商用一切后果责任由使用者自行承担。

暂无


  • No labels