从这段代码可以看出来,它08-09行会先去判断这个值是否已经在WebAppPool中有,对于第一次访问,池中显然是没有的,所以第15行构造了一个新的PortletCategory对象,并且让其读取WEB-INF/liferay-display.xml中的设定,最后和空的PortletCategory对象merge起来。
我们追述到PortletLocalServiceUtil的getEARDisplay方法中:
public static com.liferay.portal.model.PortletCategory getEARDisplay( java.lang.String xml) throws com.liferay.portal.kernel.exception.SystemException { return getService().getEARDisplay(xml); }它最终会去调用PortletLocalServiceImpl的getEARDisplay方法:
public PortletCategory getEARDisplay(String xml) throws SystemException { try { return _readLiferayDisplayXML(xml); } .. }进入调用_readLiferayDisplayXML方法,然后调用重载的_readLiferayDisplayXML(servletContextName,xml)方法:
private PortletCategory _readLiferayDisplayXML( String servletContextName, String xml) throws Exception { PortletCategory portletCategory = new PortletCategory(); if (xml == null) { xml = ContentUtil.get( "com/liferay/portal/deploy/dependencies/liferay-display.xml"); } Document document = SAXReaderUtil.read(xml, true); Element rootElement = document.getRootElement(); Set<String> portletIds = new HashSet<String>(); _readLiferayDisplay( servletContextName, rootElement, portletCategory, portletIds); // Portlets that do not belong to any categories should default to the // Undefined category Set<String> undefinedPortletIds = new HashSet<String>(); for (Portlet portlet : _getPortletsPool().values()) { String portletId = portlet.getPortletId(); PortletApp portletApp = portlet.getPortletApp(); if ((servletContextName != null) && (portletApp.isWARFile()) && (portletId.endsWith( PortletConstants.WAR_SEPARATOR + PortalUtil.getJsSafePortletId(servletContextName)) && (!portletIds.contains(portletId)))) { undefinedPortletIds.add(portletId); } else if ((servletContextName == null) && (!portletApp.isWARFile()) && (portletId.indexOf( PortletConstants.WAR_SEPARATOR) == -1) && (!portletIds.contains(portletId))) { undefinedPortletIds.add(portletId); } } if (!undefinedPortletIds.isEmpty()) { PortletCategory undefinedCategory = new PortletCategory( "category.undefined"); portletCategory.addCategory(undefinedCategory); undefinedCategory.getPortletIds().addAll(undefinedPortletIds); } return portletCategory; }从这段代码我们可以清晰的对于category的处理分为两种情况:
(1)对于liferay-display.xml中有<category>元素的分类,我们跟进第18行:
private void _readLiferayDisplay( String servletContextName, Element element, PortletCategory portletCategory, Set<String> portletIds) { for (Element categoryElement : element.elements("category")) { String name = categoryElement.attributeValue("name"); PortletCategory curPortletCategory = new PortletCategory(name); portletCategory.addCategory(curPortletCategory); Set<String> curPortletIds = curPortletCategory.getPortletIds(); for (Element portletElement : categoryElement.elements("portlet")) { String portletId = portletElement.attributeValue("id"); if (Validator.isNotNull(servletContextName)) { portletId = portletId + PortletConstants.WAR_SEPARATOR + servletContextName; } portletId = PortalUtil.getJsSafePortletId(portletId); portletIds.add(portletId); curPortletIds.add(portletId); } _readLiferayDisplay( servletContextName, categoryElement, curPortletCategory, portletIds); } }可以看出,它会循环的遍历liferay-display.xml中所有<category>元素,然后依次读取它们的<name>属性,并且把这些name属性都分别封装在PortletCategory对象中,然后把这些对象放入参数的PortletCategory中,然后递归继续读下去(PS:这是GOF中典型的Composite 设计模式)
(2) 对于liferay-display.xml中没有分类的Portlet,会归结到category.undefined分类中
PortletCategory undefinedCategory = new PortletCategory( "category.undefined");