One of the challenge of developping and maintaining a portlet container is the capability to detect deployment of portlets and create associated portlet containers. Portlet are plain java classes in a war file, the main problem is to have the portlet container to be aware of the war file deployment life cycle in order to create / destroy the associated containers.
Another challenge is to have the capability to request dispatch to a war file from another a serviced request. This can only be done if a special servlet is added to the portlet application war file. So when a portlet application is deployed, the resulting web application must contain the special portlet container servlet. It is pretty much similar to:
public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
{
// We access the context of the portlet application foo
ServletContext fooCtx = getServletContext().getContext("/foo");
// We obtain access to a servlet that will execute the portlet container
// It is important to request dispatch in order to do important stuff such
// as using objects from the foo application such as the http session or
// to have the thread context classloader of the foo application
RequestDispatcher rd = fooCtx.getRequestDispatched("/bar");
// We do an include but it should not modify the response (of course it depends on the implementation of
// the container / portal ...)
rd.include(req, resp);
}
{
// We access the context of the portlet application foo
ServletContext fooCtx = getServletContext().getContext("/foo");
// We obtain access to a servlet that will execute the portlet container
// It is important to request dispatch in order to do important stuff such
// as using objects from the foo application such as the http session or
// to have the thread context classloader of the foo application
RequestDispatcher rd = fooCtx.getRequestDispatched("/bar");
// We do an include but it should not modify the response (of course it depends on the implementation of
// the container / portal ...)
rd.include(req, resp);
}
We are able to provide solutions with different strategies, thanks to a framework that abstracts the various operations required by the portlet container and we have a couple of implementations.
We have one strategy that contains tomcat specific code and is able to detect application life cycle and modify it in a fully transparent manner. This is great for the developer as it does not require *any* modification of the portlet application, but this comes at the price of having code depending on tomcat, which is fine because tomcat is open source and we can integrate with it.
We also have a generic strategy that requires the portlet application developer to modify its war file and update the web.xml file to add a special servlet that will do all the magic. This is fine for development but this is a bit problematic when you download a thirdparty portlet application and deploy it because this forces you to edit the war file and modify it before deployment. Here is an example of what needs to be added to the war file:
<web-app>
...
<servlet>
<servlet-name>BootstrapServlet</servlet-name>
<servlet-class>org.jboss.portal.web.impl.generic.GenericBootstrapServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
...
<servlet-mapping>
<servlet-name>BootstrapServlet</servlet-name>
<url-pattern>/jbossportlet</url-pattern>
</servlet-mapping>
...
</web-app>
The nirvana is the fully transparent deployment of a portlet appliction and we are not yet there with the Servlet 3.0 spec... But the good news is that we are not far!
First the expert groups recognizes the need of the capability to modify of servlet context by providing runtime operations that will allow the addition of new servlets and create mappings dynamically:
...
servletContext.addServlet("BootstrapServlet", "The bootstrap servlet", "org.jboss.portal.web.impl.generic.GenericBootstrapServlet", null, -1);
servletContext.addServletMapping("BoostrapServlet", new String[]{"/jbossportlet"});
...
That would allow to replace the bootstrap servlet with a servlet context listener, which improves a bit the generic solution but is not yet fully transparent.
The second new feature that improves the generic solution is the modularization of web.xml, a new form a pluggability that allow to define servlets outside of web.xml in XML fragments. It is designed for frameworks. That should allow the packaging of the bootstrap servlet context listener (since now the listener could inject the servlet) in an xml fragment outside of web.xml and would allow to minimize the amount of work to do. Such xml fragments are located in the META-INF directory of any jar file bundled with the web application.
So what would become our generic implementation ? It would come as a jar file that would contain only the web xml fragment (because any portlet container classes have to be shared between all web applications...) that would be bundled in the WEB-INF/lib of the portlet application.
So we have a better generic solution now but it is not yet perfect. The expert group recognize there is a need for the various frameworks out there (even if the portlet container stuff is a special kind of framework, because of its cross context nature). When the Portlet expert group will work on a new revision of the spec, it would be great to have a solution to this problem so the Portlet spec could leverage it to provide a portable universal solution.
Personally I have a couple of suggestions in mind, I will try to blog them in the near future and maybe we could work out something with the Servlet expert group.
2 comments:
Interesting article. I have a question. If I am using the jboss portlet Container 2.0 but want to use a servlet as a controller to dispatch requests to view jsps (that are usnig the taglib to render portal markups & portlets) then what is the JBoss recommended way to approach it. Any thoughts?
Post a Comment