Skip to content

Latest commit

 

History

History
182 lines (131 loc) · 24.9 KB

layout_rendering.md

File metadata and controls

182 lines (131 loc) · 24.9 KB

Layout (page) rendering in DXP

This document explains how a request to render a page (technically named as layout) is served in DXP.

What gets requested when asking for http://localhost:8080?

First, we are going to list what external and internal requests are fired whenever someone hits DXP's root page.

Note that, in addition to the requests a browser can make to our server, the server can dispatch internal requests to resources which undergo the standard request lifecycle, simulating an external request without any need to hit the HTTP transport layer at all. Usually the responses of these internal requests are included in the originating (external) request.

All this is done leveraging the RequestDispatcher API that can be retrieved from any ServletRequest. You can see an example of how it is used in MainServlet.java.

So, whenever someone hits http://localhost:8080, the following requests are served by the application server (usually Tomcat):

Note that, in this document, we are mainly interested in the first 3 which are responsible for rendering the HTML code you see in the browser (specifically the third one, as the other two are simply forwards). The rest is listed for completeness.

path description
1 / The originating external request.
2 /web/guest Internal request to which / is forwarded. Note that you can also request /web/guest from the browser and you get the same content.
3 /c/portal/layout?p_l_id=19&p_v_l_s_g_id=0 This is internal too. The server maps the /web/guest request (which is a virtual path) to the configured layout, identified by a p_l_id. This is the request that truly generates the HTML content the user sees.
4 [/o/js_loader_config?t=<TIMESTAMP>](https://gist.github.com/wincent/bac7fec66df5a4b70c498b39fc91215b) This is a external request triggered by the HTML once the browser loads it. It returns the configuration of the AMD loader. Note that <TIMESTAMP> is a long integer value.
5 /o/classic-theme/js/main.js?browserId=firefox&minifierType=js&languageId=en_US... External request downloading the theme's JavaScript code.
6 /combo?...&/o/frontend-js-aui-web/aui/aui/aui.js&... External request downloading DXP's core JavaScript code.
7 /o/js_bundle_config?t=1600876893358 External request downloading the configuration of the legacy AUI loader.
8 /o/js_resolve_modules?... A request to resolve AMD modules. Several more of this follow as well as requests to the combo servlet to download the resolved modules.
9 /image/company_logo Request for web site logo.
10 /o/classic-theme/images/clay/icons.svg Request for Clay icon library.
11 /c/portal/login?p_l_id=19&windowState=exclusive Internal request for the login portlet.
12 /web/guest/home-widget-?p_p_id=com_liferay_login_web_portlet_LoginPortlet&... The real path serving the login's portlet response.

How layout requests are processed

There are several pieces involved in rendering a layout. We will see the details of each one in the following sections, roughly ordered by request's process timeline.

Processes any request to /c/... URLs. It reads the /WEB-INF/struts-config.xml file to configure itself with Actions, ActionForwards, ...

Processes the following paths (see the code):

	_publicPaths.add(_PATH_C);
	_publicPaths.add(_PATH_PORTAL_API_JSONWS);
	_publicPaths.add(_PATH_PORTAL_FLASH);
	_publicPaths.add(_PATH_PORTAL_J_LOGIN);
	_publicPaths.add(_PATH_PORTAL_LAYOUT);
	_publicPaths.add(_PATH_PORTAL_LICENSE);
	_publicPaths.add(_PATH_PORTAL_LOGIN);
	_publicPaths.add(_PATH_PORTAL_RENDER_PORTLET);
	_publicPaths.add(_PATH_PORTAL_TCK);
	_publicPaths.add(_PATH_PORTAL_UPDATE_LANGUAGE);
	_publicPaths.add(_PATH_PORTAL_UPDATE_PASSWORD);
	_publicPaths.add(_PATH_PORTAL_VERIFY_EMAIL_ADDRESS);
	_publicPaths.add(PropsValues.AUTH_LOGIN_DISABLED_PATH);

MainServlet delegates the handling of every GET and POST request to PortalRequestProcessor.process(), which then looks up the relevant Action and invokes it.

In addition it may redirect to the Setup Wizard or the default Error Page.

It contains a map named _definitions which is loaded from the servlet context invoking:

	servletContext.getAttribute(TilesUtil.DEFINITIONS)

and maps Struts' logical forwards (for example: portal.layout) to paths inside DXP (for example: /common/themes/portal.jsp).

It is an implementation that lives inside portal-impl and emulates the old Struts Action class. It was created to remove Struts from DXP while still retaining the old structure of Java classes and prevent migrating them to portlets, servlets, or anything similar.

Currently we have the following Actions in portal-impl (but only the LayoutAction applies to layout rendering):

Note that, because this is legacy code, we should expect no more Actions to appear in DXP's codebase.

This is another interface to emulate the support for the old Struts Action class. However, as opposed to Action which is inside portal-impl, this one lives in portal-kernel as it is intended to support OSGi modules, not DXP's core.

StrutsActions are not relevant for layout rendering purposes, but because they are the public counterpart of Action above, we mention them in this subsection.

This is the list of existing StrutActions (for reference):

  • modules/apps/archived/portal-security-wedeploy-auth-web/src/main/java/com/liferay/portal/security/wedeploy/auth/web/internal/struts/WeDeployAccessTokenStrutsAction.java
  • modules/apps/archived/portal-security-wedeploy-auth-web/src/main/java/com/liferay/portal/security/wedeploy/auth/web/internal/struts/WeDeployAuthorizeStrutsAction.java
  • modules/apps/archived/portal-security-wedeploy-auth-web/src/main/java/com/liferay/portal/security/wedeploy/auth/web/internal/struts/WeDeployUserInfoStrutsAction.java
  • modules/apps/blogs/blogs-web/src/main/java/com/liferay/blogs/web/internal/struts/RSSStrutsAction.java
  • modules/apps/bookmarks/bookmarks-web/src/main/java/com/liferay/bookmarks/web/internal/struts/FindEntryStrutsAction.java
  • modules/apps/bookmarks/bookmarks-web/src/main/java/com/liferay/bookmarks/web/internal/struts/OpenEntryStrutsAction.java
  • modules/apps/captcha/captcha-taglib/src/main/java/com/liferay/captcha/taglib/internal/struts/GetCaptchaImageStrutsAction.java
  • modules/apps/comment/comment-taglib/src/main/java/com/liferay/comment/taglib/internal/struts/EditDiscussionStrutsAction.java
  • modules/apps/comment/comment-taglib/src/main/java/com/liferay/comment/taglib/internal/struts/GetCommentsStrutsAction.java
  • modules/apps/comment/comment-taglib/src/main/java/com/liferay/comment/taglib/internal/struts/GetEditorStrutsAction.java
  • modules/apps/document-library/document-library-web/src/main/java/com/liferay/document/library/web/internal/struts/GetFileStrutsAction.java
  • modules/apps/fragment/fragment-web/src/main/java/com/liferay/fragment/web/internal/struts/ImportFragmentEntriesStrutsAction.java
  • modules/apps/fragment/fragment-web/src/main/java/com/liferay/fragment/web/internal/struts/RenderFragmentEntryStrutsAction.java
  • modules/apps/knowledge-base/knowledge-base-web/src/main/java/com/liferay/knowledge/base/web/internal/struts/FindKBArticleStrutsAction.java
  • modules/apps/layout/layout-page-template-admin-web/src/main/java/com/liferay/layout/page/template/admin/web/internal/struts/ExportLayoutPageTemplateEntriesStrutsAction.java
  • modules/apps/login/login-authentication-facebook-connect-web/src/main/java/com/liferay/login/authentication/facebook/connect/web/internal/struts/FacebookConnectStrutsAction.java
  • modules/apps/message-boards/message-boards-web/src/main/java/com/liferay/message/boards/web/internal/struts/FindRecentPostsStrutsAction.java
  • modules/apps/message-boards/message-boards-web/src/main/java/com/liferay/message/boards/web/internal/struts/RSSStrutsAction.java
  • modules/apps/portal-security-sso-google/portal-security-sso-google-login-authentication-web/src/main/java/com/liferay/portal/security/sso/google/login/authentication/web/internal/struts/GoogleLoginStrutsAction.java
  • modules/apps/subscription/subscription-web/src/main/java/com/liferay/subscription/web/internal/struts/UnsubscribeStrutsAction.java
  • modules/apps/wiki/wiki-web/src/main/java/com/liferay/wiki/web/internal/struts/GetPageAttachmentStrutsAction.java
  • modules/apps/wiki/wiki-web/src/main/java/com/liferay/wiki/web/internal/struts/RSSStrutsAction.java
  • modules/dxp/apps/oauth/oauth-web/src/main/java/com/liferay/oauth/web/internal/struts/OAuthAccessTokenStrutsAction.java
  • modules/dxp/apps/oauth/oauth-web/src/main/java/com/liferay/oauth/web/internal/struts/OAuthAuthorizeStrutsAction.java
  • modules/dxp/apps/oauth/oauth-web/src/main/java/com/liferay/oauth/web/internal/struts/OAuthRequestTokenStrutsAction.java
  • modules/dxp/apps/saml/saml-addon-keep-alive-web/src/main/java/com/liferay/saml/addon/keep/alive/web/internal/struts/KeepAliveStrutsAction.java
  • modules/dxp/apps/saml/saml-web/src/main/java/com/liferay/saml/web/internal/struts/BaseSamlStrutsAction.java
  • modules/dxp/apps/sharepoint-rest/sharepoint-rest-repository/src/main/java/com/liferay/sharepoint/rest/repository/internal/struts/SharepointOAuth2StrutsAction.java

As with portal-impl's Actions, we should expect no more StrutsActions to appear in DXP's codebase.

This is the specific Action responsible for processing all requests to /c/portal/layout and the one which renders the layout, in fact.

This is the support for the legacy Struts Tiles. It has a loadDefinitions() method which is invoked by MainServlet, upon initialization, to load TilesUtil.DEFINITIONS to be used by PortalRequestProcessor to map Struts forwards usings the _definitions map.

The Tiles defininitions are loaded from the /WEB-INF/tiles-defs.xml file.

Once an Action is executed by PortalRequestProcessor, it is very likely, that TilesUtil is invoked to get the relevant logical forward path. Whether it is invoked or not depends on how the Struts action was configured (if it relied on a Tiles or directly forwarded to a JSP page).

This is the JSP file that checks the value of the pop_up attribute in the active Tiles definition and then invokes portal_pop_up.jsp or portal_normal.jsp depending on its value. This way, the content being rendered is drawn as a popup dialog or a regular HTML page.

It can also call portal_pop_up.jsp if the current request contains a WIDGET attribute set to true (tested by themeDisplay.isWidget()). This happens when the WidgetServlet serves any URL starting with /widget/....

Also, it shows a popup when the request's windowState is POPUP (tested by themeDisplay.isStatePopUp()). See this article for more information on Liferay's window states.

This servlet listens to /widget/... URLs and reforwards whatever comes after /widget/ to be processed again but before it sets a WIDGET attribute to true in the request, so that the content is rendered using the portal_pop_up.jsp template instead of the portal_normal.jsp, as explained in the parent section.

Note, however, that not every URL can be routed through /widget/... and expect it to be shown correctly inside a popup.

This was used in the past by the Liferay.Widget API, but it is now deprecated and not used in DXP.

ThemeImpl, portal_pop_up.jsp and portal_normal.jsp

Inside portal-web/docroot/html/common/themes there used to be two core JSP files to render content. However, with the advent of themes, these two files were diverted to templates inside the active theme. So, for example, in a vanilla DXP installation they get routed to:

  • portal_pop_up.jsp: portal_pop_up.ftl
  • portal_normal.jsp: portal_normal.ftl

This mapping happens in ThemeImpl.getResourcePath().

Both FTL files should be inside the current theme, usually classic-theme or admin-theme. So, for example, there exist: