Liferay 启动过程分析7-初始化布局模板

  在MainServlet中,初始化Portlets之后,就开始初始化布局模板了,对应代码是:

  
  
  
  
  1. if (_log.isDebugEnabled()) { 
  2.             _log.debug("Initialize layout templates"); 
  3.         } 
  4.  
  5.         try { 
  6.             initLayoutTemplates(pluginPackage, portlets); 
  7.         } 
  8. .. 

 

它会调用initLayoutTemplates方法:

  
  
  
  
  1. protected void initLayoutTemplates( 
  2.             PluginPackage pluginPackage, List<Portlet> portlets) 
  3.         throws Exception { 
  4.  
  5.         ServletContext servletContext = getServletContext(); 
  6.  
  7.         String[] xmls = new String[] { 
  8.             HttpUtil.URLtoString( 
  9.                 servletContext.getResource( 
  10.                     "/WEB-INF/liferay-layout-templates.xml")), 
  11.             HttpUtil.URLtoString( 
  12.                 servletContext.getResource( 
  13.                     "/WEB-INF/liferay-layout-templates-ext.xml")) 
  14.         }; 
  15.  
  16.         LayoutTemplateLocalServiceUtil.init( 
  17.             servletContext, xmls, pluginPackage); 
  18.     } 

首先,第05行取得servlet上下文,然后第07-14行去ROOT下的/WEB-INF中去找2个XML配置文件,我看了下Liferay CE版本下的liferay-layout-template.xml,发现这里定义了2套模板,一套是<standard>,一套是<custom>,,每套下又细分为各种小模板,每种模板都用tpl文件来定义。

 

然后在第16行,调用LayoutTemplateLocalServiceUtil.init方法来读取这些xml配置文件,并且进行初始化这些模板:

  
  
  
  
  1. public static java.util.List<com.liferay.portal.kernel.util.ObjectValuePair<java.lang.String, java.lang.Boolean>> init( 
  2.     java.lang.String servletContextName, 
  3.     javax.servlet.ServletContext servletContext, java.lang.String[] xmls, 
  4.     com.liferay.portal.kernel.plugin.PluginPackage pluginPackage) { 
  5.     return getService() 
  6.                .init(servletContextName, servletContext, xmls, pluginPackage); 

 

它最终会调用LayoutTemplateLocalServiceImpl类的init()方法:

  
  
  
  
  1. public List<ObjectValuePair<String, Boolean>> init( 
  2.         String servletContextName, ServletContext servletContext, String[] xmls, 
  3.         PluginPackage pluginPackage) { 
  4.  
  5.         List<ObjectValuePair<String, Boolean>> layoutTemplateIds = 
  6.             new ArrayList<ObjectValuePair<String, Boolean>>(); 
  7.  
  8.         try { 
  9.             for (int i = 0; i < xmls.length; i++) { 
  10.                 Set<ObjectValuePair<String, Boolean>> curLayoutTemplateIds = 
  11.                     _readLayoutTemplates( 
  12.                         servletContextName, servletContext, xmls[i], 
  13.                         pluginPackage); 
  14.  
  15.                 Iterator<ObjectValuePair<String, Boolean>> itr = 
  16.                     curLayoutTemplateIds.iterator(); 
  17.  
  18.                 while (itr.hasNext()) { 
  19.                     ObjectValuePair<String, Boolean> ovp = itr.next(); 
  20.  
  21.                     if (!layoutTemplateIds.contains(ovp)) { 
  22.                         layoutTemplateIds.add(ovp); 
  23.                     } 
  24.                 } 
  25.             } 
  26.         } 
  27.         catch (Exception e) { 
  28.             _log.error(e, e); 
  29.         } 
  30.  
  31.         return layoutTemplateIds; 
  32.     } 

所以,它遍历所有xml文件(liferay-layout-template.xml和liferay-layout-template-ext.xml),并且调用_readLayoutTemplates方法来解析这些文件:

  
  
  
  
  1. private Set<ObjectValuePair<String, Boolean>> _readLayoutTemplates( 
  2.             String servletContextName, ServletContext servletContext, 
  3.             String xml, PluginPackage pluginPackage) 
  4.         throws Exception { 
  5.  
  6.         Set<ObjectValuePair<String, Boolean>> layoutTemplateIds = 
  7.             new HashSet<ObjectValuePair<String, Boolean>>(); 
  8.  
  9.         if (xml == null) { 
  10.             return layoutTemplateIds; 
  11.         } 
  12.  
  13.         Document doc = SAXReaderUtil.read(xml, true); 
  14.  
  15.         Element root = doc.getRootElement(); 
  16.  
  17.         Element standardEl = root.element("standard"); 
  18.  
  19.         if (standardEl != null) { 
  20.             readLayoutTemplate( 
  21.                 servletContextName, servletContext, layoutTemplateIds, 
  22.                 standardEl, truenull, pluginPackage); 
  23.         } 
  24.  
  25.         Element customEl = root.element("custom"); 
  26.  
  27.         if (customEl != null) { 
  28.             readLayoutTemplate( 
  29.                 servletContextName, servletContext, layoutTemplateIds, 
  30.                 customEl, falsenull, pluginPackage); 
  31.         } 
  32.  
  33.         return layoutTemplateIds; 
  34.     } 

这个解析也和Liferay解析xml文件的方式一样,用的SAXParser,然后它会去判断模板类别是standard还是custom,然后用不同的参数解析:

解析方法都是readLayoutTemplate()方法,差别就在于第5个参数,一个是true,一个是false:

读取readLayoutTemplate()方法也很长,它会去获取这个xml配置文件中的所有的<layout-template>元素,然后进行遍历。

  
  
  
  
  1. while (itr.hasNext()) { 
  2.             com.liferay.portal.kernel.xml.Element layoutTemplate = itr.next();  
  3.    ..

先获取<layout-template>的id属性,并且对其进行非null判断,并且将这些id不是null的模板id 添加到layouttemplateIds列表中。

  
  
  
  
  1. String layoutTemplateId = layoutTemplate.attributeValue("id");  
  2.  
  3.            if (layoutTemplateIds != null) {  
  4.                ObjectValuePair<String, Boolean> ovp =  
  5.                    new ObjectValuePair<String, Boolean>(  
  6.                        layoutTemplateId, standard);  
  7.  
  8.                layoutTemplateIds.add(ovp);  
  9.            }  
  10. ...

然后基于模板id来从取得模板对象或者创建一个新的:

  
  
  
  
  1. LayoutTemplate layoutTemplateModel = layoutTemplates.get( 
  2.                 layoutTemplateId); 
  3.  
  4.             if (layoutTemplateModel == null) { 
  5.                 layoutTemplateModel = new LayoutTemplateImpl(layoutTemplateId); 
  6.  
  7.                 layoutTemplates.put(layoutTemplateId, layoutTemplateModel); 
  8.             } 

然后把一些相关信息填充到新建的模板对象中,包括参数传递进来的pluginpackage信息(因为MainServlet的已经初始化了插件包,见这篇博客:http://supercharles888.blog.51cto.com/609344/906049),还有一些从模板xml配置文件中读取的其他信息:

  
  
  
  
  1. PluginSetting pluginSetting = 
  2.                 pluginSettingLocalService.getDefaultPluginSetting(); 
  3.  
  4.             layoutTemplateModel.setPluginPackage(pluginPackage); 
  5.             layoutTemplateModel.setServletContext(servletContext); 
  6.  
  7.             if (servletContextName != null) { 
  8.                 layoutTemplateModel.setServletContextName(servletContextName); 
  9.             } 
  10.  
  11.             layoutTemplateModel.setStandard(standard); 
  12.             layoutTemplateModel.setThemeId(themeId); 
  13.             layoutTemplateModel.setName(GetterUtil.getString( 
  14.                 layoutTemplate.attributeValue("name"), 
  15.                 layoutTemplateModel.getName())); 
  16.             layoutTemplateModel.setTemplatePath(GetterUtil.getString( 
  17.                 layoutTemplate.elementText("template-path"), 
  18.                 layoutTemplateModel.getTemplatePath())); 
  19.             layoutTemplateModel.setWapTemplatePath(GetterUtil.getString( 
  20.                 layoutTemplate.elementText("wap-template-path"), 
  21.                 layoutTemplateModel.getWapTemplatePath())); 
  22.             layoutTemplateModel.setThumbnailPath(GetterUtil.getString( 
  23.                 layoutTemplate.elementText("thumbnail-path"), 
  24.                 layoutTemplateModel.getThumbnailPath())); 

我们从ROOT应用的liferay-layout-template.xml中拿一段,可以很清楚看到它提取了哪些信息:

  
  
  
  
  1. <layout-template id="max"> 
  2.             <template-path>/layouttpl/standard/max.tpl</template-path> 
  3.             <wap-template-path>/layouttpl/standard/max.wap.tpl</wap-template-path> 
  4.             <thumbnail-path>/layouttpl/standard/max.png</thumbnail-path> 
  5.         </layout-template> 

吧所有必要信息都填充进模板对象之后,我们就想通过一个http请求去访问模板路径对应的模板内容,:

  
  
  
  
  1. try { 
  2.             content = HttpUtil.URLtoString(servletContext.getResource( 
  3.                 layoutTemplateModel.getTemplatePath())); 
  4.         } 
  5.         .. 

然后基于themeId,模板分类(custom还是standard),模板id 这几个字符串的值来构建velocityTemplateId:

  
  
  
  
  1. else { 
  2.                 StringBundler sb = new StringBundler(3); 
  3.  
  4.                 sb.append(themeId); 
  5.  
  6.                 if (standard) { 
  7.                     sb.append(LayoutTemplateConstants.STANDARD_SEPARATOR); 
  8.                 } 
  9.                 else { 
  10.                     sb.append(LayoutTemplateConstants.CUSTOM_SEPARATOR); 
  11.                 } 
  12.  
  13.                 sb.append(layoutTemplateId); 
  14.  
  15.                 String velocityTemplateId = sb.toString(); 

最后把上上步获取的模板的HTML内容和上步获取的velocityTemplateId都赋值给模板对象:

  
  
  
  
  1. layoutTemplateModel.setContent(content); 
  2.             layoutTemplateModel.setColumns( 
  3.                 _getColumns(velocityTemplateId, content)); 

现在,每当应用要是用某个模板对象时,它就可以很轻易的找到对应的模板代码片段内容了。

 

你可能感兴趣的:(Liferay启动过程分析)