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

Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejava
themeEclipse
firstline1
titleRepositoryProfile.java
linenumberstrue
collapsetrue
package com.fr.io.context.info;

import com.fr.cluster.ClusterBridge;
import com.fr.common.annotations.Open;
import com.fr.config.Identifier;
import com.fr.config.holder.Conf;
import com.fr.config.holder.factory.Holders;
import com.fr.config.holder.impl.MapConf;
import com.fr.config.utils.UniqueKey;
import com.fr.io.base.exception.RepositoryException;
import com.fr.io.base.provider.RepositoryFactoryProvider;
import com.fr.io.base.provider.Updatable;
import com.fr.io.config.RepositoryConfig;
import com.fr.io.context.ResourceModuleContext;
import com.fr.stable.StringUtils;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Created by rinoux on 2018/3/26.
 */
@SuppressWarnings("all")
@Open
public abstract class RepositoryProfile<T extends RepositoryConfig> extends UniqueKey implements Serializable, Updatable {

    /**
     * 仓库类型
     */
    @Identifier("identity")
    private Conf<String> identity = Holders.simple(StringUtils.EMPTY);

    /**
     * 仓库名称
     */
    @Identifier("repoName")
    private Conf<String> repoName = Holders.simple(StringUtils.EMPTY);
    /**
     * 是否集群共享
     */
    @Identifier("shared")
    private Conf<Boolean> shared = Holders.simple(Boolean.FALSE);
    /**
     * 各个机器上的工作路径,如果是共享就共用一个,非共享则各自有各自的workroot,即[id, workroot]
     */
    @Identifier("workroots")
    private MapConf<Map<String, String>> workroots = Holders.map(new HashMap<String, String>(), String.class, String.class);


    public RepositoryProfile() {
    }

    public RepositoryProfile(String identity, String repoName, String workRoot) {
        init(identity, repoName, workRoot, false);
    }


    public RepositoryProfile(String identity, String repoName, String workRoot, T config) {
        init(identity, repoName, workRoot, false);
    }

    public RepositoryProfile(String identity, String repoName, String workRoot, boolean shared) {
        init(identity, repoName, workRoot, shared);
    }


    public RepositoryProfile(String identity, String repoName, String workRoot, boolean shared, T config) {
        init(identity, repoName, workRoot, shared);
    }

    private void init(String identity, String repoName, String workRoot, boolean shared) {
        this.identity.set(identity);
        this.repoName.set(repoName);
        this.shared.set(shared);
        this.setWorkRoot(workRoot);
    }


    public String getIdentity() {
        return identity.get();
    }

    public void setIdentity(String identity) {
        this.identity.set(identity);
    }

    public String getRepoName() {
        return repoName.get();
    }

    public void setRepoName(String repoName) {
        this.repoName.set(repoName);
    }

    public String getWorkRoot() {
        String currentNodeId = ClusterBridge.getView().getCurrent().getID();
        if (workroots.containsKey(currentNodeId)) {
            return (String) workroots.get(currentNodeId);
        }
        else if (isShared()) {
            Iterator<String> iterator = workroots.get().values().iterator();
            while (iterator.hasNext()) {
                return iterator.next();
            }
        }

        return null;
    }

    public void setWorkRoot(String workRoot) {
        String currentNodeId = ClusterBridge.getView().getCurrent().getID();
        if (isShared()) {
            // 共享时改所有的 workroots
            Set<String> ids = workroots.get().keySet();
            for (String id : ids) {
                workroots.put(id, workRoot);
            }
        }
        // 改自己的
        this.workroots.put(currentNodeId, workRoot);
    }

    public boolean isShared() {
        return shared.get();
    }

    public void setShared(boolean shared) {
        this.shared.set(shared);
    }

    public abstract T getConfig();

    public abstract void setConfig(T config);



    @Override
    public RepositoryProfile<T> clone() throws CloneNotSupportedException {
        RepositoryProfile<T> cloned = (RepositoryProfile<T>) super.clone();
        cloned.identity = (Conf<String>) this.identity.clone();
        cloned.repoName = (Conf<String>) this.repoName.clone();
        cloned.shared = (Conf<Boolean>) this.shared.clone();
        cloned.workroots = (MapConf<Map<String, String>>) this.workroots.clone();

        return cloned;
    }

    /**
     * 安装并返回生产的安装组件
     *
     * @return 仓库安装组件
     * @throws RepositoryException
     */
    public InstalledComponent<T> install() {
        return ResourceModuleContext.install(this);
    }


    private boolean validate() {
        if (StringUtils.isEmpty(getIdentity())) {
            return false;
        }

        if (StringUtils.isEmpty(getRepoName())) {
            return false;
        }

        // 不共享但是没有本机的workroot
        if (!isShared() && StringUtils.isEmpty(getWorkRoot())) {
            return false;
        }

        // 共享但是没有workroot配置
        if (isShared() && workroots.get().isEmpty()) {
            return false;
        }

        return true;
    }


    /**
     * 是否适合本机安装
     *
     * @return
     */
    public boolean suitable() {
        if (ResourceModuleContext.getFactory(getIdentity()) == null) {
            return false;
        }
        return validate();
    }

    @Override
    public final void update(String srcRepo) {
        InstalledComponent c = ResourceModuleContext.getInstalledComponent(srcRepo);
        this.setWorkRoot(c.getWorkRoot());
        this.setShared(c.isShared());
        if (getConfig() != null) {
            this.getConfig().update(srcRepo);
        }
    }

    /**
     * 仅生成安装组件(不安装)
     *
     * @return 仓库安装组件
     */
    public final InstalledComponent<T> generateComponent() {
        RepositoryFactoryProvider<T> fac = ResourceModuleContext.getFactory(getIdentity());
        return new InstalledComponent<T>(fac, getRepoName(), getWorkRoot(), isShared());
    }

}

可通过三组常见引入JS和CSS的插件接口对比引入以下JS接口

Code Block
languagejs
themeEclipse
firstline1
title前端接口
linenumberstrue
!(function () {
    BI.config("dec.constant.intelligence.cluster.file.server", function (items) {
        items.push({
            value: "DEMO", //跟后台的RepositoryConfig#identity值一致
            id: "decision-intelligence-cluster-file-demo",// 定一个前端唯一的ID值【下拉框选项】
            text: "DEMO REPOSITORY",//该类型文件服务器的显示值【下拉框选项】
            cardType: "dec.intelligence.cluster.file.demo"//配置文件服务器的组件
        });
        return items;
    });
	//下面是定义配置的组件getValue/validation 是该组件必须要实现的方法
    var LABEL_WIDTH = 116, EDITOR_WIDTH = 300;
    var DEMO = BI.inherit(BI.Widget, {
        ...

        render: function () {
            var self = this, o = this.options;
            return {
                type: "bi.vertical",
                tgap: 15,
                items: [
                    {
                        type: "dec.label.editor.item",
                        textWidth: LABEL_WIDTH,
                        editorWidth: EDITOR_WIDTH,
                        watermark: BI.i18nText("Dec-Please_Input"),
                        text: "ROOT",
                        value: this.model.root,//初始化显示配置的值
                        ref: function (_ref) {
                            self.rootRow = _ref;
                        },
                        listeners: [{
                            eventName: BI.Editor.EVENT_CHANGE,
                            action: function () {
                                self.store.setRoot(this.getValue());
                            }
                        }]
                    }]
            };
        },
        getValue: function () {//getValue返回的值对应后台的config接口的实现。变量名跟后台config的GetConifg和SetConfig注解的value一致
            return {
                root: this.model.root//保存配置的值
            };
        },
        validation: function () {//异常判断
            var valid = true, root = this.model.root;
            if (BI.isEmpty(root)) {
                this.rootRow.showError(BI.i18nText("Dec-Error_Null"));
                valid = false;
            }
            return valid;
        }
    });
    ...
})();


四、支持版本

产品线

版本

支持情况

备注

FR10.0支持

五、插件注册

Code Block
languagexml
themeEclipse
firstline1
titleplugin.xml
linenumberstrue
<extra-core>
        <AlternateResultProvider<ResourceRepositoryFactoryProvider class="your class name"/>
</extra-core>


六、原理说明

文件服务器本身逻辑较为底层,涉及的相关引入和初始化及调用逻辑较为复杂,故本文不做单独介绍。

如DmlController和SynchronizedLiveDataModelUtils所示,当共享数据集调用缓存数据时会先从插件中查找,找不到再到产品的缓存中查找;填报缓存失效时,会调用对于的插件扩展缓存插件移除对于的缓存。

调用均通过Set<AlternateResultProvider> set = ExtraClassManager.getInstance().getArray(AlternateResultProvider.XML_TAG);获取到所有插件中申明的自定义缓存策略接口实例。

七、特殊限制说明

用于共享数据集缓存策略扩展场景时,开发者需要使用其他接口对数据进行缓存。因为标准产品中只调用了读缓存,没有直接提供写缓存的调用,需要借助其他插件接口来生成并写入缓存。以及监控缓存的生命周期。

...

七、特殊限制说明

该接口的本质就是通过抽象的定义了一组文件操作接口方法,来适配各类文件存储媒介。

要实现的接口很多,但最终其实都是为调用ResourceRepository接口中操作文件的各种方法展开的

ResourceRepositoryFactoryProvider 是插件注册的入口,提供一个文件服务器的工厂给决策平台

RepositoryConfig是最终的自定义的文件存储媒介的可变配置对象。

RepositoryProfile则是前置的决策平台内部的一个文件服务器的配置对象,它包含了RepositoryConfig。

八、常用链接

demo地址:demo-resource-alternaterepository-resultfactory-provider

三组常见引入JS和CSS的插件接口对比

九、开源案例

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