/ 初始化
portal.servlet.MainServlet.init()
// process startup events
StartupAction.run()
// 初始化portlets.
String[] xmls = new String[] {
Http.URLtoString(ctx.getResource("/WEB-INF/portlet.xml")),
Http.URLtoString(ctx.getResource("/WEB-INF/portlet-ext.xml")),
Http.URLtoString(ctx.getResource("/WEB-INF/liferay-portlet.xml")),
Http.URLtoString(ctx.getResource("/WEB-INF/liferay-portlet-ext.xml")),
Http.URLtoString(ctx.getResource("/WEB-INF/web.xml"))
};
PortletLocalServiceUtil.initEAR(xmls)
// 初始化display.
String xml = Http.URLtoString(ctx.getResource(
"/WEB-INF/liferay-display.xml"));
PortletCategory newPortletCategory =
PortletLocalServiceUtil.getEARDisplay(xml);
portletCategory.merge(newPortletCategory);
// 初始化layout模板.
String[] xmls = new String[] {
Http.URLtoString(ctx.getResource(
"/WEB-INF/liferay-layout-templates.xml")),
Http.URLtoString(ctx.getResource(
"/WEB-INF/liferay-layout-templates-ext.xml"))
};
LayoutTemplateLocalUtil.init(ctx, xmls)
// 初始化Theme.
String[] xmls = new String[] {
Http.URLtoString(ctx.getResource(
"/WEB-INF/liferay-look-and-feel.xml")),
Http.URLtoString(ctx.getResource(
"/WEB-INF/liferay-look-and-feel-ext.xml"))
};
ThemeLocalUtil.init(ctx, xmls)
// 检查company
CompanyLocalServiceUtil.checkCompany(_companyId);
// 其它内容...
// 响应服务
portal.servlet.MainServlet.service()
// get portalContext
ServletContext ctx = getServletContext();
ServletContext portalCtx = ctx.getContext(
PrefsPropsUtil.getString(_companyId, PropsUtil.PORTAL_CTX));
// Struts module config
ModuleConfig moduleConfig = getModuleConfig(req);
// Portlet Request Processor - 在struts.config中定义.
portletReqProcessor = PortletRequestProcessor.getInstance(this, moduleConfig);
// 登录处理.
// 处理service前置事件.
EventsProcessor.process(PropsUtil.getArray(PropsUtil.SERVLET_SERVICE_EVENT_PRE), req, res);
// 调用Struts的service方法.
callParentService(req, res);
// 处理Sruts后置事件.
EventsProcessor.process(PropsUtil.getArray(PropsUtil.SERVLET_SERVICE_EVENTS_POST), req, res);
// struts的ActionServlet.
ActionServlet.process(HttpServletRequest req, HttpServletResponse res)
processor.process(req, res);
// portal的RequestProcessor.
portal.struts.PortalRequestProcessor.process(HttpServletRequest req, HttpServletResponse res)
// struts的RequestProcessor
RequestProcessor.process(HttpServletRequest req, HttpServletResponse res)
string path = processPath(req, res) // PortalRequestProcessor重载
ActionMapping mapping = processMapping(req, res, path);
processRoles(req, res, mapping) // PortalRequestProcessor重载
ActionForm from = processActionForm(req, res, mapping);
processForward(req, res, mapping);
processInclude(req, res, mapping);
Action action = processActionCreate(req, res, mapping);
ActionForward forward = processActionPerform(req, res, action, form, mapping);
processForwardConfig(req, res, forward); // TilesRequestProcessor重载
// tiles的RequestProcessor
TilesRequestProcessor.processForwardConfig(req, res, forward)
processTilesDefinition(forward.getPath(), forward.getContextRelative(), req, res);
Controller.execute(); // 输出/portal/layout.jsp
/html/portal/layout.jsp - portal布局页面.
此处include在/portal-ejb/classes/portal.properties里layout.view.page定义的页面/portal/layout/view/portlet.jsp
/html/portal/layout/view/portlet.jsp - portlet布局视图页面.
// 读取模板内容,模板由liferay-layout-templates.xml文件定义.
String content = LayoutTemplateLocalUtil.getContent(
layoutTypePortlet.getLayoutTemplateId(), false, theme.getThemeId());
下面是一个一列的模板:
<div id="layout-content-outer-decoration">
<div id="layout-content-inner-decoration">
<div id="layout-content-container">
$processor.processColumn("column-1")
</div>
</div>
</div>
// 处理模板
portlet.layoutconfiguration.util.RuntimePortletUtil.processTemplate(
application, pageContext, request, response, content);
// 注入模板处理程序
TemplateProcessor processor = new TemplateProcessor(ctx, req, res, portletId);
VelocityContext context = new VelocityContext();
context.put("processor", processor);
// 处理模板
Velocity.evaluate(context, pageContext.getOut(),
RuntimePortletUtil.class.getName(), content);
/ /处理各列
portlet.layoutconfiguration.util.velocity.TemplateProcessor.processColumn(
String columnId) throws Exception {
HashMap attributes = new HashMap();
attributes.put("id", columnId);
RuntimeLogic logic = new PortletColumnLogic(_ctx, _req, _res);
StringBuffer sb = new StringBuffer();
logic.processContent(sb, attributes);
return sb.toString();
}
// 处理列内容
portlet.layoutconfiguration.util.velocity.PortletColumnLogic.processContent(
StringBuffer sb, Map attributes) throws Exception {
String columnId = (String)attributes.get("id");
sb.append("<div id=/"layout-column_");
sb.append(columnId);
sb.append("/">");
LayoutTypePortlet layoutTypePortlet =
_themeDisplay.getLayoutTypePortlet();
// 取得当前列的所有portlet.
List portlets = layoutTypePortlet.getAllPortlets(columnId);
// 处理各portlet.
for (int i = 0; i < portlets.size(); i++) {
Portlet portlet = (Portlet)portlets.get(i);
String rootPortletId = portlet.getRootPortletId();
String instanceId = portlet.getInstanceId();
RuntimePortletUtil.processPortlet(
sb, _ctx, _req, _res, null, null, rootPortletId, instanceId,
columnId, new Integer(i), new Integer(portlets.size()));
}
sb.append("<div class=/"layout-blank-portlet/"></div>");
sb.append("</div>");
}
// 处理Portlet.
portlet.layoutconfiguration.util.RuntimePortletUtil.processPortlet(
StringBuffer sb, ServletContext ctx, HttpServletRequest req,
HttpServletResponse res, RenderRequest renderRequest,
RenderResponse renderResponse, String portletId, String instanceId,
String columnId, Integer columnPos, Integer columnCount)
throws Exception {
ThemeDisplay themeDisplay =
(ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
Portlet portlet = PortletLocalServiceUtil.getPortletById(
themeDisplay.getCompanyId(), portletId);
if ((portlet != null) && portlet.isInstanceable()) {
if (Validator.isNotNull(instanceId) &&
Validator.isPassword(instanceId) &&
(instanceId.length() == 4)) {
portletId +=
Portlet.INSTANCE_SEPARATOR + instanceId;
portlet = PortletLocalServiceUtil.getPortletById(
themeDisplay.getCompanyId(), portletId);
}
else {
if (_log.isDebugEnabled()) {
_log.debug(
"Portlet " + portlet.getPortletId() +
" is instanceable but does not have a " +
"valid instance id");
}
portlet = null;
}
}
if (portlet == null) {
return;
}
// Capture the current portlet's settings to reset them once the child
// portlet is rendered
PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
PortletDisplay portletDisplayClone =
(PortletDisplay)portletDisplay.clone();
PortletConfig portletConfig =
(PortletConfig)req.getAttribute(WebKeys.JAVAX_PORTLET_CONFIG);
try {
PortalUtil.renderPortlet(
sb, ctx, req, res, portlet, columnId, columnPos, columnCount);
}
finally {
portletDisplay.copyFrom(portletDisplayClone);
PortletDisplayFactory.recycle(portletDisplayClone);
_defineObjects(
req, portletConfig, renderRequest, renderResponse);
}
}
portal.util.PortalUtil.renderPortlet(
StringBuffer sb, ServletContext ctx, HttpServletRequest req,
HttpServletResponse res, Portlet portlet, String columnId,
Integer columnPos, Integer columnCount)
throws IOException, ServletException {
columnId = GetterUtil.getString(columnId);
if (columnPos == null) {
columnPos = new Integer(0);
}
if (columnCount == null) {
columnCount = new Integer(0);
}
req.setAttribute(WebKeys.RENDER_PORTLET, portlet);
req.setAttribute(WebKeys.RENDER_PORTLET_COLUMN_ID, columnId);
req.setAttribute(WebKeys.RENDER_PORTLET_COLUMN_POS, columnPos);
req.setAttribute(WebKeys.RENDER_PORTLET_COLUMN_COUNT, columnCount);
RequestDispatcher rd = ctx.getRequestDispatcher(
"/html/portal/render_portlet.jsp");
if (sb != null) {
StringServletResponse stringServletRes =
new StringServletResponse(res);
rd.include(req, stringServletRes);
sb.append(stringServletRes.getString());
}
else {
// LEP-766
String strutsCharEncoding =
PropsUtil.get(PropsUtil.STRUTS_CHAR_ENCODING);
req.setCharacterEncoding(strutsCharEncoding);
res.setContentType(Constants.TEXT_HTML + "; charset=UTF-8");
rd.include(req, res);
}
}
/html/portal/render_portlet.jsp - Portlet输出页面。
Portlet portlet = (Portlet)request.getAttribute(WebKeys.RENDER_PORTLET);
CachePortlet cachePortlet = PortletInstanceFactory.create(portlet, application);
PortletPreferences portletPrefs = PortletPreferencesLocalServiceUtil.getPreferences(
company.getCompanyId(), PortletPreferencesFactory.getPortletPreferencesPK(request, portletId));
PortletConfig portletConfig = PortletConfigFactory.create(portlet, application);
PortletContext portletCtx = portletConfig.getPortletContext();
HttpServletRequest originalReq = PortalUtil.getOriginalServletRequest(request);
RenderRequestImpl renderRequestImpl = RenderRequestFactory.create(
originalReq, portlet, cachePortlet, portletCtx, windowState, portletMode, portletPrefs, plid);
StringServletResponse stringServletRes = new StringServletResponse(response);
RenderResponseImpl renderResponseImpl = RenderResponseFactory.create(
renderRequestImpl, stringServletRes, portletId, company.getCompanyId(), plid);
renderRequestImpl.defineObjects(portletConfig, renderResponseImpl);
if (portlet.isActive() && access) {
try {
cachePortlet.render(renderRequestImpl, renderResponseImpl);
}
catch (UnavailableException ue) {
portletException = true;
PortletInstanceFactory.destroy(portlet);
}
}
%>
<div id="p_p_id<%= renderResponseImpl.getNamespace() %>"
class="portlet-boundary portlet-boundary<%= PortalUtil.getPortletNamespace(portlet.getRootPortletId()) %>">
<a name="p_<%= portletId %>"></a>
<script type="text/javascript">
var portletEl = document.getElementById("p_p_id<%= renderResponseImpl.getNamespace() %>");
portletEl.portletId = "<%= portletId %>";
portletEl.isStatic = <%= portlet.isStatic() || !showMoveIcon %>;
portletEl.isStaticStart = <%= portlet.isStaticStart() %>;
portletEl.isStaticEnd = <%= portlet.isStaticEnd() %>;
</script>
<c:choose>
<c:when test="<%= !access && !portlet.isShowPortletAccessDenied() %>">
</c:when>
<c:when test="<%= !portlet.isActive() && !portlet.isShowPortletInactive() %>">
</c:when>
<c:otherwise>
<%
boolean useDefaultTemplate = portlet.isUseDefaultTemplate();
Boolean useDefaultTemplateObj = renderResponseImpl.getUseDefaultTemplate();
if (useDefaultTemplateObj != null) {
useDefaultTemplate = useDefaultTemplateObj.booleanValue();
}
//cachePortlet不为空并且为StrutsPortlet.
if ((cachePortlet != null) && cachePortlet.isStrutsPortlet()) {
if (!access || portletException) { // 不能访问或出错!
String templatePath = Constants.TEXT_HTML_DIR + "/common/themes/portlet.jsp";
if (definition != null) {
templatePath = Constants.TEXT_HTML_DIR + definition.getPath();
}
%>
<tiles:insert template="<%= templatePath %>" flush="false">
<tiles:put name="portlet_content" value="/portal/portlet_error.jsp" />
</tiles:insert>
<%
}
else {
if (useDefaultTemplate) {
// 通过Tiles输出portlet内容.
renderRequestImpl.setAttribute(WebKeys.PORTLET_CONTENT, stringServletRes.getString());
%>
<tiles:insert template='<%= Constants.TEXT_HTML_DIR + "/common/themes/portlet.jsp" %>' flush="false">
<tiles:put name="portlet_content" value="<%= StringPool.BLANK %>" />
</tiles:insert>
<%
}
else { // 直接输出portlet内容.
pageContext.getOut().print(stringServletRes.getString());
}
}
}
else {
renderRequestImpl.setAttribute(WebKeys.PORTLET_CONTENT, stringServletRes.getString());
String portletContent = StringPool.BLANK;
if (portletException) {
portletContent = "/portal/portlet_error.jsp";
}
%>
<c:choose>
<c:when test="<%= useDefaultTemplate || portletException %>">
<tiles:insert template='<%= Constants.TEXT_HTML_DIR + "/common/themes/portlet.jsp" %>' flush="false">
<tiles:put name="portlet_content" value="<%= portletContent %>" />
</tiles:insert>
</c:when>
<c:otherwise>
<%= renderRequestImpl.getAttribute(WebKeys.PORTLET_CONTENT) %>
</c:otherwise>
</c:choose>
<%
}
%>
</c:otherwise>
</c:choose>
</div>
/html/common/themes/portlet.jsp - Portlet主题页面
// 处理tilesPortletContent
<tiles:useAttribute id="tilesPortletContent" name="portlet_content" classname="java.lang.String" ignore="true" />
<tiles:useAttribute id="tilesPortletDecorate" name="portlet_decorate" classname="java.lang.String" ignore="true" />
<tiles:useAttribute id="tilesPortletPadding" name="portlet_padding" classname="java.lang.String" ignore="true" />
<%
Portlet portlet = (Portlet)request.getAttribute(WebKeys.RENDER_PORTLET);
PortletPreferences portletSetup = PortletPreferencesFactory.getPortletSetup(
request, portletDisplay.getId(), true, true);
RenderResponseImpl renderResponseImpl = (RenderResponseImpl)renderResponse;
String currentURL = PortletURLUtil.getCurrent(renderRequest, renderResponse).toString();
// Portlet decorate
boolean tilesPortletDecorateBoolean = GetterUtil.getBoolean(tilesPortletDecorate, true);
boolean portletDecorate = GetterUtil.getBoolean(
portletSetup.getValue("portlet-setup-show-borders", String.valueOf(tilesPortletDecorateBoolean)));
Properties cssProps = PropertiesUtil.load(portletSetup.getValue("portlet-setup-css", StringPool.BLANK));
%>
<c:if test="<%= (cssProps != null) && (cssProps.size() > 0) %>">
<%@ include file="/html/common/themes/portlet_css.jsp" %>
</c:if>
<%
// Portlet title, 标题
String portletTitle = portletSetup.getValue("portlet-setup-title", StringPool.BLANK);
if (portletDisplay.isAccess() && portletDisplay.isActive()) {
if (Validator.isNull(portletTitle)) {
portletTitle = renderResponseImpl.getTitle();
}
}
if (Validator.isNull(portletTitle)) {
ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
portletTitle = resourceBundle.getString(WebKeys.JAVAX_PORTLET_TITLE);
}
portletDisplay.setTitle(portletTitle);
// URL configuration, 配置链接
PortletURLImpl urlConfiguration = new PortletURLImpl(request, PortletKeys.PORTLET_CONFIGURATION, plid, false);
urlConfiguration.setWindowState(WindowState.MAXIMIZED);
if (Validator.isNotNull(portlet.getConfigurationPath())) {
urlConfiguration.setParameter("struts_action", "/portlet_configuration/edit_configuration");
}
else {
urlConfiguration.setParameter("struts_action", "/portlet_configuration/edit_look_and_feel");
}
urlConfiguration.setParameter("portletResource", portletDisplay.getId());
urlConfiguration.setParameter("redirect", currentURL);
portletDisplay.setURLConfiguration("javascript: self.location = '" +
Http.encodeURL(urlConfiguration.toString()) + "&" +
PortalUtil.getPortletNamespace(PortletKeys.PORTLET_CONFIGURATION) +
"previewWidth=' + document.getElementById('p_p_id" +
portletDisplay.getNamespace() + "').offsetWidth;");
// URL close, 关闭链接
String urlClose = "javascript: closePortlet('" + plid + "', '" + portletDisplay.getId() + "');";
portletDisplay.setURLClose(urlClose.toString());
// URL edit, 编辑链接
PortletURLImpl urlEdit = new PortletURLImpl(request, portletDisplay.getId(), plid, false);
if (portletDisplay.isModeEdit()) {
urlEdit.setWindowState(WindowState.NORMAL);
urlEdit.setPortletMode(PortletMode.VIEW);
}
else {
if (portlet.isMaximizeEdit()) {
urlEdit.setWindowState(WindowState.MAXIMIZED);
}
else {
urlEdit.setWindowState(WindowState.NORMAL);
}
urlEdit.setPortletMode(PortletMode.EDIT);
}
portletDisplay.setURLEdit(urlEdit.toString());
// URL guest edit, 匿名编辑链接
PortletURLImpl urlEditGuest = new PortletURLImpl(request, portletDisplay.getId(), plid, false);
if (portletDisplay.isModeEditGuest()) {
urlEditGuest.setWindowState(WindowState.NORMAL);
urlEditGuest.setPortletMode(PortletMode.VIEW);
}
else {
if (portlet.isMaximizeEdit()) {
urlEditGuest.setWindowState(WindowState.MAXIMIZED);
}
else {
urlEditGuest.setWindowState(WindowState.NORMAL);
}
urlEditGuest.setPortletMode(LiferayPortletMode.EDIT_GUEST);
}
portletDisplay.setURLEditGuest(urlEditGuest.toString());
// URL help, 帮助链接
PortletURLImpl urlHelp = new PortletURLImpl(request, portletDisplay.getId(), plid, false);
if (portletDisplay.isModeHelp()) {
urlHelp.setWindowState(WindowState.NORMAL);
urlHelp.setPortletMode(PortletMode.VIEW);
}
else {
if (portlet.isMaximizeHelp()) {
urlHelp.setWindowState(WindowState.MAXIMIZED);
}
else {
urlHelp.setWindowState(WindowState.NORMAL);
}
urlHelp.setPortletMode(PortletMode.HELP);
}
portletDisplay.setURLHelp(urlHelp.toString());
// URL max, 最大化链接
boolean action = !portletDisplay.isRestoreCurrentView();
PortletURLImpl urlMax = new PortletURLImpl(request, portletDisplay.getId(), plid, action);
if (portletDisplay.isStateMax()) {
urlMax.setWindowState(WindowState.NORMAL);
}
else {
urlMax.setWindowState(WindowState.MAXIMIZED);
}
if (!action) {
String portletNamespace = portletDisplay.getNamespace();
Map renderParameters = RenderParametersPool.get(request, plid, portletDisplay.getId());
Iterator itr = renderParameters.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry entry = (Map.Entry)itr.next();
String key = (String)entry.getKey();
if (key.startsWith(portletNamespace)) {
key = key.substring(portletNamespace.length(), key.length());
String[] values = (String[])entry.getValue();
urlMax.setParameter(key, values);
}
}
}
portletDisplay.setURLMax(urlMax.toString());
// URL min, 最小化链接
String urlMin = "javascript: minimizePortlet('" + plid + "', '" +
portletDisplay.getId() + "', " + portletDisplay.isStateMin() + ");";
portletDisplay.setURLMin(urlMin);
// URL print, 打印链接
PortletURLImpl urlPrint = new PortletURLImpl(request, portletDisplay.getId(), plid, false);
if (portletDisplay.isModePrint()) {
urlPrint.setWindowState(WindowState.NORMAL);
urlPrint.setPortletMode(PortletMode.VIEW);
}
else {
if (portlet.isMaximizePrint()) {
urlPrint.setWindowState(WindowState.MAXIMIZED);
}
else {
urlPrint.setWindowState(WindowState.NORMAL);
}
urlPrint.setPortletMode(LiferayPortletMode.PRINT);
}
portletDisplay.setURLPrint(urlPrint.toString());
// URL back, 后退链接
String urlBack = null;
if (portletDisplay.isModeEdit()) {
urlBack = urlEdit.toString();
}
else if (portletDisplay.isModeHelp()) {
urlBack = urlHelp.toString();
}
else if (portletDisplay.isModePrint()) {
urlBack = urlPrint.toString();
}
else if (portletDisplay.isStateMax()) {
if (portletDisplay.getId().equals(PortletKeys.PORTLET_CONFIGURATION)) {
String portletResource = ParamUtil.getString(request, "portletResource");
urlMax.setAnchor(false);
urlBack = urlMax.toString() + "#p_" + portletResource;
}
else {
urlBack = urlMax.toString();
}
}
if (urlBack != null) {
portletDisplay.setShowBackIcon(true);
portletDisplay.setURLBack(urlBack);
}
%>
<c:choose>
<c:when test="<%= !portletDisplay.isStatePopUp() %>"> // 是否弹窗? 弹窗不显示标题栏.
<c:choose>
<c:when test="<%= portletDecorate %>">
<liferay-theme:box top="portlet_top.jsp" bottom="portlet_bottom.jsp">
<div id="p_p_content<%= portletDisplay.getNamespace() %>" style="margin-top: 0; margin-bottom: 0;">
<%@ include file="/html/common/themes/portlet_content.jsp" %>
</div>
</liferay-theme:box>
</c:when>
<c:otherwise>
<div class="portlet-borderless-container">
<c:if test="<%= tilesPortletDecorateBoolean && portletDisplay.isShowConfigurationIcon() %>">
<div class="portlet-borderless-bar">
<span class="portlet-title-default"><%= portletTitle %></span>
- <a href="<%= portletDisplay.getURLConfiguration() %>"><bean:message key="configuration" /></a>
<c:if test="<%= portletDisplay.isShowEditIcon() %>">
- <a href="<%= portletDisplay.getURLEdit() %>"><bean:message key="preferences" /></a>
</c:if>
<c:if test="<%= portletDisplay.isShowCloseIcon() %>">
- <a href="<%= portletDisplay.getURLClose() %>"><bean:message key="close" /></a>
</c:if>
</div>
</c:if>
<%@ include file="/html/common/themes/portlet_content.jsp" %>
</div>
</c:otherwise>
</c:choose>
</c:when>
<c:otherwise>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td <%= portletPadding ? "style=/"padding: 4px 8px 10px 8px;/"" : "" %>>
<c:if test="<%= Validator.isNotNull(tilesPortletContent) %>">
<liferay-util:include page="<%= Constants.TEXT_HTML_DIR + tilesPortletContent %>" />
</c:if>
<c:if test="<%= Validator.isNull(tilesPortletContent) %>">
<%
pageContext.getOut().print(renderRequest.getAttribute(WebKeys.PORTLET_CONTENT));
%>
</c:if>
</td>
</tr>
</table>
</c:otherwise>
</c:choose>
/html/common/themes/portlet_content.jsp - portlet内容页面.
<c:if test="<%= portletDisplay.isActive() %>">
<c:if test="<%= portletDisplay.isAccess() %>">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td <%= portletPadding ? "style=/"padding: 4px 8px 10px 8px;/"" : "" %>>
<c:if test='<%= !tilesPortletContent.endsWith("/error.jsp") %>'>
<%@ include file="/html/common/themes/portlet_messages.jsp" %>
</c:if>
<c:if test="<%= Validator.isNotNull(tilesPortletContent) %>">
<liferay-util:include page="<%= Constants.TEXT_HTML_DIR + tilesPortletContent %>" />
</c:if>
<c:if test="<%= Validator.isNull(tilesPortletContent) %>">
<%
pageContext.getOut().print(renderRequest.getAttribute(WebKeys.PORTLET_CONTENT));
%>
</c:if>
</td>
</tr>
</table>
</c:if>
<c:if test="<%= !portletDisplay.isAccess() %>">
<liferay-util:include page="/html/portal/portlet_access_denied.jsp" />
</c:if>
</c:if>