Friday, March 23, 2012

Liferay's 3 Servlets Musketeers (PortalActionServlet, PortalServlet and MainServlet)

MainServlet

This is the main servlet in Liferay, it handles all request directed to the portal itself, mapped to '/c/*' as in Liferay's ROOT web.xml. Together with various FriendlyURLServlet mappings in web.xml, they almost handle all the happenings in Liferay. FriendlyURLServlet normally analyze friendly urls and do a redirect after regenerating friendly urls back to the complex form that Liferay happens to understand through PortalUtil

PortletServlet

This is the servlet that will get autogenerated during deployment of Portlet Plugins WAR file. It is really just a simple proxy pumping in resources to your portlet. Checkout PortletAutoDeployer on how it is written to your Portlet Plugin WAR's web.xml during hot deployment. Remember that the whole Portlet framework is after all based on Servlet specs, this Servlet gives Liferay a way to push through resources to a specific portlet.

PortalActionServlet

In short, forget about this Servlet, it is a legacy Servlet as far as my understanding goes. Why? All it does is make sure a copy of PortletRequestProcessor (sounds familiar? yes, its an extension of Struts's RequestProcessor) is available in ServletContext under WebKey.PORTLET_STRUTS_PROCESSOR. This is now (Liferay 6.1.x) being taken care of in MainServlet.checkRequestProcessor method. Think of it this way. Where does your portlet lives? Inside a Portal container of course. Any request to your portlet have to go through a Portal container first, and that means going through MainServlet which will make sure a copy of PortletRequestProcessor is available nicely before eventually hitting your portlet. Humbly think that this is a nicer way rather than having each Portlet WAR file declaring a PortletActionServlet, cause the following is how PortletActionServlet stick a copy of PortletRequestProcessor into ServletContext

                ServletContext servletContext = getServletContext();

                ModuleConfig moduleConfig =
                        (ModuleConfig)servletContext.getAttribute(Globals.MODULE_KEY);

                PortletRequestProcessor portletRequestProcessor =
                        PortletRequestProcessor.getInstance(this, moduleConfig);

                servletContext.setAttribute(
                        WebKeys.PORTLET_STRUTS_PROCESSOR, portletRequestProcessor);
It's coupling in Struts's specific way of looking up ModuleConfig into it's code, which arguable isn't going to change much in the near future anyway but still ... I think it's tight coupling

This is how it's done in MainServlet.checkPortletRequestProcessor(...)

                ServletContext servletContext = getServletContext();

                PortletRequestProcessor portletReqProcessor =
                        (PortletRequestProcessor)servletContext.getAttribute(
                             WebKeys.PORTLET_STRUTS_PROCESSOR);

                if (portletReqProcessor == null) {
                        ModuleConfig moduleConfig = getModuleConfig(request);

                        portletReqProcessor =
                              PortletRequestProcessor.getInstance(this, moduleConfig);

                        servletContext.setAttribute(
                              WebKeys.PORTLET_STRUTS_PROCESSOR, portletReqProcessor);
  }

which is doing it through getModuleConfig(request) methods relying on Struts's ActionServlet to provide the implementation and hence abstracting it away from potential future changes in implementation

This are really just my understandings on briefly digging into Liferay's source through occasionally a VI on a terminal over a glass of red or coffee during spare times over lunch break or weekends. If you disagree in anyway, I'd love to be corrected.

Anyway Liferay looks like a promising portal solution and I would definitely be exploring further

No comments:

Post a Comment