portlet.xml
portlet定义描述文件,它描述portlet的类型,支持Mode, preferenes和role等,遵循JSR168标准实现,以便于移植(需要针对性的做一些小改过)。
下面是一个简单的定义:
<portlet>
<portlet-name>2</portlet-name>
<display-name>My Account</display-name>
<!-- portlet的实现类 -->
<portlet-class>com.liferay.portlet.StrutsPortlet</portlet-class>
<init-param>
<name>view-action</name>
<value>/my_account/view</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<resource-bundle>com.liferay.portlet.StrutsResourceBundle</resource-bundle>
</portlet>
在JSR168标准中,定义了view/edit/help三种模式,
liferay对其进行了扩展,增加了config/about/preview/print等模式。
liferay-portlet.xml
liferay的portlet定义描述文件,是liferay对portlet.xml的扩展描述,允许我们对portlet的呈现、功能和行为进行更深入的定制。
它与com.liferay.portal.model.Portlet类对应,
下面是一个较为详细的liferay-portlet定义:
<portlet>
<portlet-name>19</portlet-name>
<!-- struts路径 -->
<struts-path>message_boards</struts-path>
<!-- 配置路径 -->
<configuration-path>/message_boards/edit_configuration</configuration-path>
<!-- lucene索引类 -->
<indexer-class>com.liferay.portlet.messageboards.util.Indexer</indexer-class>
<!-- url处理类 -->
<portlet-url-class>com.liferay.portlet.messageboards.MBFriendlyPortletURL</portlet-url-class>
<!-- 友好url插件类 -->
<friendly-url-plugin-class>com.liferay.portlet.messageboards.MBFriendlyURLPortletPlugin</friendly-url-plugin-class>
<preferences-unique-per-layout>false</preferences-unique-per-layout>
<use-default-template>false</use-default-template>
<restore-current-view>false</restore-current-view>
<private-request-attributes>false</private-request-attributes>
</portlet>
portlet类中常用的属性:
// strtus 路径,对portlet的请求应该限制在这个路径下
private String _strutsPath;
// 配置路径,即action定义
private String _configurationPath;
// portlet实现类
private String _portletClass;
// lucene索引类
private String _indexerClass;
// scheduler类
private String _schedulerClass;
// portletURL处理类
private String _portletURLClass;
// friendURL插件
private String _friendlyURLPluginClass;
// 默认的preferences
private String _defaultPreferences;
// preferences的验证类
private String _prefsValidator;
// 是否实例化,为true时可添加多个portlet到layout上
private boolean _instanceable;
// 是否为系统portlet,
private boolean _system;
// 初始化参数
private Map _initParams;
// portlet支持的模式
private Map _portletModes;
// portlet支持的语言
private Set _supportedLocales;
// PortletInfo
private PortletInfo _portletInfo;
// 是否静态portlet, 静态portlet不能移动.
private boolean _staticPortlet;
// 是否为开始的静态portlet.
private boolean _staticPortletStart;
portlet解析
com.liferay.portal.service.impl.PortletLocalServiceImpl
public void initEAR(String[] xmls) {
String scpId = PortletServiceImpl.class.getName() + "." + _SHARED_KEY;
Map portletsPool = (Map)SimpleCachePool.get(scpId);
if (portletsPool == null) {
portletsPool = CollectionFactory.getSyncHashMap();
SimpleCachePool.put(scpId, portletsPool);
}
try {
List servletURLPatterns = _readWebXML(xmls[4]);
Set portletIds =
_readPortletXML(xmls[0], portletsPool, servletURLPatterns);
portletIds.addAll(
_readPortletXML(xmls[1], portletsPool, servletURLPatterns));
Set liferayPortletIds =
_readLiferayPortletXML(xmls[2], portletsPool);
liferayPortletIds.addAll(
_readLiferayPortletXML(xmls[3], portletsPool));
// Check for missing entries in liferay-portlet.xml
// 检查在liferay-portlet中丢失的portlet实体...
// Remove portlets that should not be included
// 移去不应该包括的portlet实体...
}
catch (Exception e) {
_log.error(StackTraceUtil.getStackTrace(e));
}
}
// 解析portlet.xml
private Set _readPortletXML(
String servletContextName, String xml, Map portletsPool,
List servletURLPatterns)
throws DocumentException, IOException {
Set portletIds = new HashSet();
if (xml == null) {
return portletIds;
}
SAXReader reader = SAXReaderFactory.getInstance();
Document doc = reader.read(new StringReader(xml));
Element root = doc.getRootElement();
Set userAttributes = new HashSet();
Iterator itr1 = root.elements("user-attribute").iterator();
// 用户属性处理...
itr1 = root.elements("portlet").iterator();
while (itr1.hasNext()) {
Element portlet = (Element)itr1.next();
String portletId = portlet.elementText("portlet-name");
if (servletContextName != null) {
portletId =
portletId + Portlet.WAR_SEPARATOR + servletContextName;
}
portletId = PortalUtil.getJsSafePortletName(portletId);
if (_log.isDebugEnabled()) {
_log.debug("Reading portlet " + portletId);
}
portletIds.add(portletId);
Portlet portletModel = (Portlet)portletsPool.get(portletId);
if (portletModel == null) {
portletModel = new Portlet(
new PortletPK(portletId, _SHARED_KEY));
portletsPool.put(portletId, portletModel);
}
if (servletContextName != null) {
portletModel.setWARFile(true);
}
if (servletURLPatterns != null) {
portletModel.setServletURLPatterns(servletURLPatterns);
}
portletModel.setPortletClass(portlet.elementText("portlet-class"));
Iterator itr2 = portlet.elements("init-param").iterator();
// 初始化参数处理...
Element expirationCache = portlet.element("expiration-cache");
// cache过期处理...
itr2 = portlet.elements("supports").iterator();
// 支持模式处理...
Set supportedLocales = portletModel.getSupportedLocales();
// 支持语言处理...
// 资源
portletModel.setResourceBundle(
portlet.elementText("resource-bundle"));
Element portletInfo = portlet.element("portlet-info");
// portlet-info处理...
Element portletPreferences = portlet.element("portlet-preferences");
// preferences处理...
Set unlikedRoles = portletModel.getUnlinkedRoles();
itr2 = portlet.elements("security-role-ref").iterator();
// role处理...
portletModel.getUserAttributes().addAll(userAttributes);
}
return portletIds;
}
// 解析liferay-portlet.xml
private Set _readLiferayPortletXML(
String servletContextName, String xml, Map portletsPool)
throws DocumentException, IOException {
Set liferayPortletIds = new HashSet();
if (xml == null) {
return liferayPortletIds;
}
SAXReader reader = SAXReaderFactory.getInstance();
Document doc = reader.read(new StringReader(xml));
Element root = doc.getRootElement();
Map roleMappers = new HashMap();
Iterator itr1 = root.elements("role-mapper").iterator();
// role-mapper处理...
Map customUserAttributes = new HashMap();
itr1 = root.elements("custom-user-attribute").iterator();
// 定制用户属性处理...
Map friendlyURLPlugins = _getFriendlyURLPlugins();
itr1 = root.elements("portlet").iterator();
while (itr1.hasNext()) {
Element portlet = (Element)itr1.next();
String portletId = portlet.elementText("portlet-name");
if (servletContextName != null) {
portletId =
portletId + Portlet.WAR_SEPARATOR + servletContextName;
}
portletId = PortalUtil.getJsSafePortletName(portletId);
if (_log.isDebugEnabled()) {
_log.debug("Reading portlet extension " + portletId);
}
liferayPortletIds.add(portletId);
Portlet portletModel = (Portlet)portletsPool.get(portletId);
if (portletModel != null) {
// 设置portlet属性...
// 处理FriendURL插件
portletModel.setFriendlyURLPluginClass(GetterUtil.getString(
portlet.elementText("friendly-url-plugin-class"),
portletModel.getFriendlyURLPluginClass()));
if (Validator.isNull(
portletModel.getFriendlyURLPluginClass())) {
friendlyURLPlugins.remove(portletId);
}
else {
friendlyURLPlugins.put(
portletId, portletModel.getFriendlyURLPluginClass());
}
// 绑定role.
portletModel.getRoleMappers().putAll(roleMappers);
portletModel.linkRoles();
portletModel.getCustomUserAttributes().putAll(
customUserAttributes);
}
}
return liferayPortletIds;
}
从上面的代码可看出,liferay将portlet的描述定义存储在一个Map中.
liferay-display.xml
portlet的类别定义文件,下面是一个简单的例子:
<category name="category.admin">
<portlet id="9" />
<portlet id="40" />
<portlet id="79" />
<portlet id="80" />
</category>
要注意的是,在portlet.xml/liferay-portlet.xml/liferay-display.xml三个文件中的portlet-name, portlet-id必须是一致的。
liferay-layout-templates.xml
layout模板定义文件.
liferay-look-and-feel.xml
主题定义文件.
portlet的web.xml
如果以war的方式发布portlet,那么它的web.xml也要进行一些特定的说明,
下面是liferay中sample-jsp-portlet示例的web.xml:
<web-app>
<display-name>sample-jsp-portlet</display-name>
<context-param>
<param-name>company_id</param-name>
<param-value>liferay.com</param-value>
</context-param>
<listener>
<listener-class>com.liferay.portal.kernel.servlet.PortletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>sample_jsp_portlet</servlet-name>
<servlet-class>com.liferay.portal.kernel.servlet.PortletServlet</servlet-class>
<init-param>
<param-name>portlet-class</param-name>
<param-value>com.sample.jsp.portlet.JSPPortlet</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>sample_jsp_portlet</servlet-name>
<url-pattern>/sample_jsp_portlet/*</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>http://java.sun.com/portlet</taglib-uri>
<taglib-location>/WEB-INF/tld/liferay-portlet.tld</taglib-location>
</taglib>
</web-app>
上面的listener是必须的,它用于通知liferay进行热部署,
portlet-class指定Portlet的实现类,它必须遵循JSR168标准,直接或间接的从javax.portlet.GenericPortlet继承。