229 lines
9.3 KiB
XML
229 lines
9.3 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<chapter id="portlet">
|
|
<title>Portlet Integration</title>
|
|
<sect1 id="portlet-introduction">
|
|
<title>Introduction</title>
|
|
<para>
|
|
This chapter shows you how to use Web Flow in a Portlet environment.
|
|
Web Flow has full support for JSR-168 portlets.
|
|
The <code>booking-portlet-mvc</code> sample application is a good reference for using Web Flow within a portlet.
|
|
This application is a simplified travel site that allows users to search for and book hotel rooms.
|
|
</para>
|
|
</sect1>
|
|
<sect1 id="portlet-config-core">
|
|
<title>Configuring web.xml & portlet.xml</title>
|
|
<para>
|
|
The configuration for a portlet depends on the portlet container used.
|
|
The <code>booking-portlet-mvc</code> and <code>booking-portlet-faces</code> sample application are both configured to use <ulink url="http://portals.apache.org/pluto/">Apache Pluto</ulink>, the JSR-168 reference implementation.
|
|
</para>
|
|
<para>
|
|
In general the configuration requires adding a servlet mapping in the <code>web.xml</code> file to dispatch request to the portlet container.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<servlet>
|
|
<servlet-name>swf-booking-mvc</servlet-name>
|
|
<servlet-class>org.apache.pluto.core.PortletServlet</servlet-class>
|
|
<init-param>
|
|
<param-name>portlet-name</param-name>
|
|
<param-value>swf-booking-mvc</param-value>
|
|
</init-param>
|
|
<load-on-startup>1</load-on-startup>
|
|
</servlet>
|
|
|
|
<servlet-mapping>
|
|
<servlet-name>swf-booking-mvc</servlet-name>
|
|
<url-pattern>/PlutoInvoker/swf-booking-mvc</url-pattern>
|
|
</servlet-mapping>
|
|
]]></programlisting>
|
|
<para>
|
|
The <code>portlet.xml</code> configuration is a standard portlet configuration.
|
|
The <code>portlet-class</code> needs to be set along with a pair of <code>init-param</code>s.
|
|
Setting the <code>expiration-cache</code> to <code>0</code> is recommended to force Web Flow to always render a fresh view.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<portlet>
|
|
...
|
|
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
|
|
<init-param>
|
|
<name>contextConfigLocation</name>
|
|
<value>/WEB-INF/web-application-config.xml</value>
|
|
</init-param>
|
|
<init-param>
|
|
<name>viewRendererUrl</name>
|
|
<value>/WEB-INF/servlet/view</value>
|
|
</init-param>
|
|
<expiration-cache>0</expiration-cache>
|
|
...
|
|
</portlet>
|
|
]]></programlisting>
|
|
</sect1>
|
|
<sect1 id="portlet-config-spring">
|
|
<title>Configuring Spring</title>
|
|
<sect2 id="portlet-config-spring-handler">
|
|
<title>Flow Handlers</title>
|
|
<para>
|
|
The only supported mechanism for bridging a portlet request to Web Flow is via a <code>FlowHandler</code>.
|
|
The <code>PortletFlowController</code> used in Web Flow 1.0 is no longer supported.
|
|
</para>
|
|
<para>
|
|
The flow handler, similar to the servlet flow handler, provides hooks that can:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>select the flow to execute</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>pass input parameters to the flow on initialization</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>handle the flow execution outcome</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>handle any exceptions</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
The <code>AbstractFlowHandler</code> class is an implementation of <code>FlowHandler</code> that provides default implementations for these hooks.
|
|
</para>
|
|
<para>
|
|
In a portlet environment the targeted flow id can not be inferred from the URL and must be defined explicitly in the handler.
|
|
</para>
|
|
<programlisting language="java"><![CDATA[
|
|
public class ViewFlowHandler extends AbstractFlowHandler {
|
|
public String getFlowId() {
|
|
return "view";
|
|
}
|
|
}
|
|
]]></programlisting>
|
|
</sect2>
|
|
<sect2 id="portlet-config-spring-mappings">
|
|
<title>Adapter Mappings</title>
|
|
<para>
|
|
Spring Portlet MVC provides a rich set of methods to map portlet requests.
|
|
Complete documentation of the available methods is available in the <ulink url="http://static.springframework.org/spring/docs/2.5.x/reference/portlet.html#portlet-handlermapping">Spring Reference Documentation</ulink>.
|
|
</para>
|
|
<para>
|
|
The <code>booking-portlet-mvc</code> sample application uses a <code>PortletModeHandlerMapping</code> to map portlet requests.
|
|
The sample application only supports <code>view</code> mode, but support for other portlet modes is available.
|
|
Other modes can be added and point to the same flow as <code>view</code> mode, or any other flow.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
|
|
<property name="portletModeMap">
|
|
<map>
|
|
<entry key="view">
|
|
<bean class="org.springframework.webflow.samples.booking.ViewFlowHandler" />
|
|
</entry>
|
|
</map>
|
|
</property>
|
|
</bean>
|
|
]]></programlisting>
|
|
</sect2>
|
|
<sect2 id="portlet-config-spring-handler-adapter">
|
|
<title>Flow Handler Adapter</title>
|
|
<para>
|
|
A <code>FlowHandlerAdapter</code> converts the handler mappings to the flow handlers.
|
|
The flow executor is required as a constructor argument.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<bean id="flowHandlerAdapter" class="org.springframework.webflow.mvc.portlet.FlowHandlerAdapter">
|
|
<constructor-arg ref="flowExecutor" />
|
|
</bean>
|
|
]]></programlisting>
|
|
</sect2>
|
|
<sect2 id="portlet-config-spring-redirectonpause">
|
|
<title>Redirect on Pause</title>
|
|
<para>
|
|
In a portlet environemnt, <code>alwaysRedirectOnPause</code> must be set to <code>false</code>.
|
|
If not turned off, the initial view will fail to render.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
|
|
<webflow:flow-execution-attributes>
|
|
<webflow:alwaysRedirectOnPause value="false"/>
|
|
</webflow:flow-execution-attributes>
|
|
</webflow:flow-executor>
|
|
]]></programlisting>
|
|
</sect2>
|
|
</sect1>
|
|
<sect1 id="portlet-views">
|
|
<title>Portlet Views</title>
|
|
<para>
|
|
In order to facilitate view rendering, a <code>ViewRendererServlet</code> must be added to the <code>web.xml</code> file.
|
|
This servlet is not invoked directly, but it used by Web Flow to render views in a portlet environment.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<servlet>
|
|
<servlet-name>ViewRendererServlet</servlet-name>
|
|
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
|
|
</servlet>
|
|
|
|
<servlet-mapping>
|
|
<servlet-name>ViewRendererServlet</servlet-name>
|
|
<url-pattern>/WEB-INF/servlet/view</url-pattern>
|
|
</servlet-mapping>
|
|
]]></programlisting>
|
|
</sect1>
|
|
<sect1 id="portlet-modes">
|
|
<title>Portlet Modes and Window States</title>
|
|
<sect2 id="portlet-modes-state">
|
|
<title>Window State</title>
|
|
<para>
|
|
The Portlet API defined three window states: normal, minimized and maximized.
|
|
The portlet implementation must decide what to render for each of these window states.
|
|
Web Flow exposes the string value of the window state under <code>portletWindowState</code> via the request map on the external context.
|
|
</para>
|
|
<programlisting language="java"><![CDATA[
|
|
requestContext.getExternalContext().getRequestMap().get("portletWindowState");
|
|
]]></programlisting>
|
|
<programlisting language="el"><![CDATA[
|
|
${externalContext.requestMap.portletWindowState}
|
|
]]></programlisting>
|
|
</sect2>
|
|
<sect2 id="portlet-modes-mode">
|
|
<title>Portlet Mode</title>
|
|
<para>
|
|
The Portlet API defined three portlet modes: view, edit and help.
|
|
The portlet implementation must decide what to render for each of these modes.
|
|
Web Flow exposes the string value of the portlet mode under <code>portletMode</code> via the request map on the external context.
|
|
</para>
|
|
<programlisting language="java"><![CDATA[
|
|
requestContext.getExternalContext().getRequestMap().get("portletMode");
|
|
]]></programlisting>
|
|
<programlisting language="el"><![CDATA[
|
|
${externalContext.requestMap.portletMode}
|
|
]]></programlisting>
|
|
</sect2>
|
|
</sect1>
|
|
<sect1 id="portlet-issues">
|
|
<title>Issues in a Portlet Environment</title>
|
|
<sect2 id="portlet-issues-redirects">
|
|
<title>Redirects</title>
|
|
<para>
|
|
The Portlet API only allows redirects to be requested from an action request.
|
|
Because views are rendered on the render request, views and <code>view-state</code>s cannot trigger a redirect.
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="portlet-issues-modes">
|
|
<title>Switching Portlet Modes</title>
|
|
<para>
|
|
The portlet container passes the execution key from the previous flow when switching to a new mode.
|
|
Even if the mode is mapped to a different <code>FlowHandler</code> the flow execution will resume the previous execution.
|
|
</para>
|
|
<para>
|
|
One way to start the new flow is to create a URL targeting the mode without the execution key.
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="portlet-issues-jsf">
|
|
<title>Portlets and JSF</title>
|
|
<para>
|
|
Web Flow supports JSF as the view technology for a portlet.
|
|
However, a jsf-portlet bridge (JSR-301) must be provided.
|
|
At the time of this writing, no feature complete jsf-portlet bridge exists.
|
|
Some of the existing bridge implementations may appear to work, however, strange side effect may occur.
|
|
</para>
|
|
<para>
|
|
JSF portlets are considered experimental at this time.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter>
|