其实在ZK的早期版本中是没有WebManager这个类的,它负责的功能都在DHtmlLayoutServlet中,后来许是开发者觉得这样DHtmlLayoutServlet的责任就太重了,所以按照每个类只做一件事情的思想把有些功能转移到了WebManager中,这也使得ZK软件本身的层次更加清晰。正如ZK文档中所描述的WebManager是Web服务器和ZK之间的桥梁,每一个使用zk的web应用程序都有一个独立且唯一的WebManager实例。WebManager初始化(通过构造方法)
WebManager(ServletContext ctx, String updateURI){……}
主要完成以下工作:
第一、从metainfo/zk/config.xml(位于ZK的发行包中)和WEB-INF/zk.xml中加载配置,config.xml的源码如下
<?xml version="1.0" encoding="UTF-8"?> <config> <config-name>zk</config-name><!-- used to resolve dependency --> <version> <version-class>org.zkoss.zk.Version</version-class> <version-uid>3.5.0</version-uid> </version> <!-- Note: zscript-config is applied to the whole system. Not just this language. --> <zscript-config> <language-name>Java</language-name> <interpreter-class>org.zkoss.zk.scripting.bsh.BSHInterpreter</interpreter-class> </zscript-config> <device-config> <device-type>ajax</device-type> <device-class>org.zkoss.zk.device.AjaxDevice</device-class> <unavailable-message><![CDATA[ <p style="color:red">Sorry, JavaScript must be enabled.<br/>Change your browser options, then <a href="">try again</a>.</p> ]]></unavailable-message> </device-config> </config>
它配置的信息包括版本、脚本语言解释器以及设备,可以看出Java是zk默认的脚本语言,除此之外通过引入解释器这一概念,zk还支持Javascript、Groovy及Ruby语言等,在此不做详细介绍;Device描述了客户端的设备类型,其中使用Ajax的HTML浏览器被称作AjaxDevice,XML输出被称作org.zkoss.zml.device.XmlDevice。
第二、往Labels中注册一个新的LabelLocator并设置变量解析器为ServletLabelResovler。
Labels.register(new ServletLabelLocator(_ctx));
Labels.setVariableResolver(new ServletLabelResovler())
其中,VariableResolver用于指定表达式(org.zkoss.xel.Expression)在计算时解析变量引用的方式;Labels是用于访问标签(Label)的帮助类,一个Label就是一个与Local有关的字符串,被存放在类似i3-label*.properties的文件中,一旦一个LabelLocator被注册到Labels中,LabelLoader就会通过调用locate(java.util.Locale)去定位任何额外的资源,例如下面是ServletLabelLocator中的部分源码:
//-- LabelLocator --//
public URL locate(Locale locale) throws IOException {
return _ctx.getResource("/WEB-INF/"+getI3LabelName(locale));
}
/** Returns the filename of i3-label.properties. */
private static final String getI3LabelName(Locale locale) {
return locale.equals(Locale.ENGLISH) ?
"i3-label.properties": "i3-label_" + locale + ".properties";
}
可以看出ServletLabelLocator主要用于加载WEB-INF/下所有与i3-label相关的property属性文件,
和我们一般的本地化策略有所不同,假如属性文件中的信息是中文这里没必要通过native2ascii命令将中文转换为ascii码,例如下面分别是zkdemo中WEB-INF/下i3-label.properties与i3-label_zh_CN.properties的源码
#--------------------# # Label for zkdemo # #--------------------# username=Username password=Password
#--------------------# # Label for zkdemo # #--------------------# username=用户 password=密码
第三、创建一个WebApp实例(默认为org.zkoss.zk.ui.http.SimpleWebApp)并初始化
((WebAppCtrl)_wapp).init(_ctx, config);
第四、初始化ClassWebResource并加载适当的Extendlet(作为ClassWebResource的插件用于处理特殊的内容)。
_cwr = ClassWebResource.getInstance(_ctx, _updateURI);
_cwr.setCompress(new String[] {"js", "css", "html", "xml"});
_ctx.setAttribute(ATTR_WEB_MANAGER, this);
_cwr.setDebugJS(config.isDebugJS());
//Register resource processors for each extension
//FUTURE: Extendlet can be specified in zk.xml
//Note: getAll loads config.xml, which must be processed before zk.xml
ZumlExtendlet extlet = null;
for (Iterator it = LanguageDefinition.getAll().iterator();it.hasNext();) {
final LanguageDefinition langdef = (LanguageDefinition)it.next();
final List exts = langdef.getExtensions();
if (!exts.isEmpty()) {
if (extlet == null)
extlet = new ZumlExtendlet();
_cwr.addExtendlet((String)exts.get(0), extlet);
//Add to the first extension only (the main one)
}
}
第五、删除所有与ServletContext相关的WebManagerActivationListener并对要删除的每个WebManagerActivationListener调用didActivate(WebManager webman)方法。
((WebManagerActivationListener)it.next()).didActivate(this);
附:WebManager所持有重要私有属性
/** Map(ServletContext, List(WebManagerActivationListener)). */
private static final Map _actListeners = new HashMap();
private final ServletContext _ctx;
private final WebApp _wapp;
private final String _updateURI;
private final ClassWebResource _cwr;