2021SC@SDUSC
sitemap-impl文件夹分析(2)
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、总结
帮助从 PipelineNode 和 PipelinesNode 调用错误处理程序
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、主要属性
- 生命周期相关对象
//该组件的 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();
- 视图管理
//每个标签的视图名称集合
private Map labelViews = new HashMap();
//视图的伪标签 from-position="first"
public static final String FIRST_POS_LABEL = "!first!";
//判断当前是否在构建视图的标志位,默认为false
private boolean isBuildingView = false;
- 其他参数
//通过 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