2021SC@SDUSC【软件工程应用与实践】Cocoon项目13——sitemap-impl文件夹分析(2)

2021SC@SDUSC

AbstractMetaModule.java

1、总结

AbstractMetaModule 为您提供了轻松部署更多“元”InputModules 的基础架构,即由其他 InputModules 组成的 InputModules。 为了获得记录器,请使用 getLogger()

2、主要属性

//服务管理器实例
protected ServiceManager manager;
//缓存输入模块选择器
protected ServiceSelector inputSelector;
//缓存默认输入模块
protected InputModule input;
//默认 InputModule 名称/速记,默认为“请求参数”
protected String defaultInput = "request-param"; 
//默认的 InputModule 配置,在 configure() 期间将成为一个空的配置对象
protected Configuration inputConf; 
//判断这个实例是否进行初始化的标志位
protected boolean initialized = false;
//操作码
private final static int OP_GET = 0;
private final static int OP_VALUES = 1;
private final static int OP_NAMES = 2;

3、方法

public synchronized void lazy_initialize() {
        try {
            if (!this.initialized) {
                this.inputSelector = (ServiceSelector)this.manager.lookup(INPUT_MODULE_SELECTOR); 
                if (this.defaultInput != null) {
                    this.input = obtainModule(this.defaultInput);
                }
                this.initialized = true;
            }
        } catch (Exception e) {
            if (getLogger().isWarnEnabled()) 
                getLogger().error("A problem occurred setting up input modules :'" + e.getMessage(), e);
        }
    } 
  • 使用另一个输入模块初始化元模块。 由于“元”模块需要对相同角色的组件的引用,因此在实现 ThreadSafe 时无法在 initialize() 中完成初始化,因为此时组件选择器尚未初始化,它将触发创建一个新的,导致无休止的 初始化循环。 因此,如果模块本身尚未初始化,则每个模块在第一次需要访问另一个模块时都需要调用此方法。 覆盖此方法和 dispose() 以保持对多个模块的引用
  • 获取输入模块对其进行初始化,调用obtainModule获取该模块的永久引用,并将标志位initialized改为已完成初始化
public void dispose()
  • 只处理一个缓存的 InputModule, 要处理多个,请覆盖此方法并 initialize()
protected InputModule obtainModule(String type)
  • 获取对 InputModule 的永久引用
  • 检查输入选择器是否已经被查找过
private Object get(int op, String attr, Map objectModel,
                         InputModule staticMod, String staticModName, Configuration staticModConf,
                         InputModule dynamicMod, String dynamicModName, Configuration dynamicModConf)
throws ConfigurationException
  • 封装 InputModule 的使用,执行所有查找等操作
  • 如果第二个模块(动态)具有非空名称,则首选它。如果遇到异常,则打印警告消息并返回 null
  • 参数op:要执行的操作(OP_GET、OP_NAMES、OP_VALUES)
  • 返回:一个对象、一个对象[]或一个迭代器,取决于op参数

ErrorHandlerHelper.java

1、总结

帮助从 PipelineNodePipelinesNode 调用错误处理程序

2、主要属性

//处理错误的记录器
protected Log handledErrorsLogger;
//所有其他异常的错误处理节点
private HandleErrorsNode error;

3、方法

public Processor.InternalPipelineDescription prepareErrorHandler(Exception ex,
Environment env,InvokeContext context)
             throws Exception
  • 为内部管道错误处理准备错误处理程序
  • 如果只构建管道,将构建并返回错误处理管道。如果构建和执行管道,将构建和执行错误处理管道
  • internal && !isInternal()==true时根据内部请求传播异常:无内部处理程序;!internal && !isExternal()==true时传播外部请求异常:无外部处理程序;否则此错误处理程序未处理异常,传播
 private Processor.InternalPipelineDescription prepareErrorHandler(ProcessingNode node, Exception ex, Environment env, InvokeContext context)
        throws Exception {
        if (ex instanceof ResourceNotFoundException) {
            this.handledErrorsLogger.error(ex.getMessage());
        } else {
            this.handledErrorsLogger.error(ex.getMessage(), ex);
        }
        try {
            prepare(context, env, ex);
            // 创建错误上下文
            InvokeContext errorContext = new InvokeContext(context, this.manager);
            try {
                // 进程错误处理节点
                if (node.invoke(env, errorContext)) {
                    // 异常被处理
                    return errorContext.getInternalPipelineDescription(env);
                }
            } finally {
                errorContext.dispose();
            }
        } catch (Exception e) {
            getLogger().error("An exception occured while handling errors at " + node.getLocation(), e);
            // 重新抛出它:它将由父站点地图或环境(例如 Cocoon servlet)处理
            throw e;
        }
        // 异常未在此错误处理程序中处理,传播
        throw ex;
}
  • 使用指定的错误处理程序处理节点准备(或执行)错误处理程序
  • 如果只构建管道,将构建并返回错误处理管道。如果构建和执行管道,将构建和执行错误处理管道
  • prepare(context, env, ex)构建通知对象,当错误之前没有被另一个处理程序处理过的情况下,尝试重置响应以避免混合已经产生的输出和错误页面,构建成狗后将其添加到对象模型
  • dispose():释放管道,如果有的话,如果它们被这个上下文查找

SitemapLanguage.java

1、总结

站点地图语言的树构建器
继承自AbstractLogEnabled
实现了TreeBuilder, Contextualizable, Serviceable,Recyclable接口

2、主要属性

  1. 生命周期相关对象
//该组件的 avalon 上下文
private Context context;
//该组件的服务管理器
private ServiceManager manager;
//正在构建的树处理器
protected ConcreteTreeProcessor processor;
//正在构建的处理器的配置命名空间
protected String itsNamespace;
//正在构建的处理器的服务管理器
private ServiceManager itsManager;
//Helper 对象,它在正在构建的处理器的上下文中设置组件
private LifecycleHelper itsLifecycle;
//在正在构建的处理器的上下文中设置的 ProcessingNodeBuilders 选择器
private NodeBuilderSelector itsBuilders;
//构建itsManger时抓取的站点地图组件信息
protected PipelineComponentInfo itsComponentInfo;
//输入站点地图事件的可选事件侦听器
protected List enterSitemapEventListeners = new ArrayList();
//离开站点地图事件的可选事件侦听器
protected List leaveSitemapEventListeners = new ArrayList();
  1. 视图管理
//每个标签的视图名称集合
private Map labelViews = new HashMap();
//视图的伪标签 from-position="first"
public static final String FIRST_POS_LABEL = "!first!";
//判断当前是否在构建视图的标志位,默认为false
private boolean isBuildingView = false;
  1. 其他参数
//通过 setupNode() 实现 Initializable 的节点
private List initializableNodes = new ArrayList();
//通过 setupNode() 实现 Disposable 的节点
private List disposableNodes = new ArrayList();
//由 createNodeBuilder() 创建的 NodeBuilders 实现 LinkedProcessingNodeBuilder
private List linkedBuilders = new ArrayList();
//是否处于允许注册节点的状态标志位
private boolean canGetNode = false;
//使用 registerNode() 注册的节点
private Map registeredNodes = new HashMap();

3、方法

protected String getBuilderConfigURL()
  • 获取 treebuilder 配置文件的位置。可以覆盖其他版本
public List getLeaveSitemapEventListeners()
  • 返回为 org.apache.cocoon.sitemap.LeaveSitemapEvent 注册的所有事件列表
  • 返回的是被复制的ArrayList 实例的浅表副本(元素本身不会被复制),以便我们可以在站点地图构建后清除(回收)列表
protected ProcessingNode createTree(Configuration tree) throws Exception
  • 一旦设置了组件管理器和节点构建器,就创建树。 可以被子类覆盖以执行前/后树创建操作
  • 从顶级元素创建节点构建器,调用buildNode()从给定的配置构建 ProcessingNode 及其子节点构建整棵树,并可选地在树构建器中注册它以供其他 LinkedProcessingNodeBuilder查找
protected void linkNodes() throws Exception
  • 解析链接:在所有链接处理 NodeBuilder 上调用 linkNode()。 可以被子类覆盖以执行前/后解析操作
  • 在链接节点之前,查找 getViewNodes(Collection) 中使用的视图类别节点
public List getDisposableNodes()
  • 返回此树中 Disposable 的 ProcessingNodes 部分的列表。 在丢弃加工树之前,应注意妥善处理它们
public ProcessingNode build(Configuration tree, String location) throws Exception {
fam.setSitemapNotifier(this.processor.getWrappingProcessor());
        final Monitor fam = null;
        this.itsContainer = SitemapHelper.createContainer(
                                               tree,
                                               location,
                                               fam,
                                               (ServletContext)this.context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT));
        final Context itsContext = (Context)this.itsContainer.getBean(AvalonUtils.CONTEXT_ROLE);
        // 整个站点地图中使用的命名空间是根元素之一
        this.itsNamespace = tree.getNamespace();
        // 是否需要替换属性
        if ( tree.getChild("components").getAttributeAsBoolean("replace-properties", true) ) {
            tree = AvalonUtils.replaceProperties(tree, (Settings)this.itsContainer.getBean(Settings.ROLE));
        }
        this.itsManager = (ServiceManager) this.itsContainer.getBean(AvalonUtils.SERVICE_MANAGER_ROLE);
        // 注册监听器
        this.registerListeners();

        this.itsComponentInfo = (PipelineComponentInfo) this.itsManager.lookup(PipelineComponentInfo.ROLE);
        // 创建一个辅助对象来设置组件
        this.itsLifecycle = new LifecycleHelper(null /* logger */, itsContext, this.itsManager, null /* configuration */);
        // 创建并初始化 NodeBuilder 选择器
        {
            NodeBuilderSelector selector = new NodeBuilderSelector();
            //加载构建器配置文件
            SourceResolver resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
            String url = getBuilderConfigURL();
            Configuration config;
            try {
                Source src = resolver.resolveURI(url);
                try {
                    SAXConfigurationHandler handler = new SAXConfigurationHandler();
                    SourceUtil.toSAX(this.manager, src, null, handler);
                    config = handler.getConfiguration();
                } finally {
                    resolver.release(src);
                }
            } catch (Exception e) {
                throw new ConfigurationException("Could not load TreeBuilder configuration from " +
                                                 url, e);
            } finally {
                this.manager.release(resolver);
            }
            LifecycleHelper.setupComponent(selector,
                                           getLogger(), itsContext, this.itsManager,
                                           config.getChild("nodes", false));
            
            this.itsBuilders = selector;
        }
        // 禁止调用 getRegisteredNode()
        this.canGetNode = false;
        // 收集所有一次性变量解析器        VariableResolverFactory.setDisposableCollector(this.disposableNodes);

        ProcessingNode result = createTree(tree);

        // 现在允许调用 getRegisteredNode()
        this.canGetNode = true;
        linkNodes();
        // 初始化所有可初始化节点
        Iterator iter = this.initializableNodes.iterator();
        while (iter.hasNext()) {
            ((Initializable) iter.next()).initialize();
        }
        return result;
}
  • 从配置构建处理树,具体实现过程如代码中备注
public ProcessingNode setupNode(ProcessingNode node, Configuration config) throws Exception
  • 通过设置它的位置来设置一个 ProcessingNode,调用它实现的所有生命周期接口,如果它是一个 ParameterizableNode 则给它参数映射
  • 为方便起见,此方法返回节点以允许像 return treeBuilder.setupNode(new MyNode(), config) 这样的构造
public void addViewForLabel(String label, String view)
  • 为标签添加视图,这用于注册从给定标签开始的所有视图
  • 参数label:视图的标签(或伪标签)
public Collection getViewsForStatement(String role, String hint, Configuration statement)
            throws Exception
  • 获取给定语句的视图名称。 如果返回的集合中存在cocoon视图,则语句可以直接跳转到视图处理节点
  • 过程:计算附加到这个组件的视图,为该语句的所有标签构建集合(标签类型:①在组件上定义的标签,②在此语句中定义的标签,③取决于角色的伪标签),构建附加到这些标签的视图集,并迭代此语句的所有标签
  • 参数role:组件角色(例如 Generator.ROLE)
  • 参数hint:组件提示,即“类型”属性
public Map getHintsForStatement(String role, String hint, Configuration statement)
            throws Exception
  • 从给定的语句中提取管道提示(如果存在)
  • 返回此语句的提示参数映射,如果不存在则为 null
  • 这个方法实现了hintParam语法如下:
    1.一个提示属性有一个或多个逗号分隔的提示
    2.提示是名称和可选(字符串)值,如果没有值,则认为是布尔字符串“true”
    3.提示 :: 文字 [ ‘=’ 文字 ],文字 :: <不允许使用字符 ‘,’ 和 ‘=’ 的字符串>
    4.如果“解析”提示出现问题,则会抛出 ConfigurationException
  • 注意:首先,确定是否在组件级别定义了任何管道提示,如果是,则继承这些管道提示(这些提示可以被本地管道提示覆盖),如果没有定义管道提示,那么继续下去是没有意义的,返回 null
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值