<?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 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 and portlet.xml</title>
		<para>
			The configuration for a portlet depends on the portlet container used.
			The sample applications, included with Web Flow, 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 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 exceptions</para>
					</listitem>
				</itemizedlist>
			</para>
			<para>
				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>Handler Mappings</title>
			<para>
				Spring Portlet MVC provides a rich set of methods to map portlet requests.
				Complete documentation  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>
	</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><![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><![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.
				You may switch the mode programatically in your FlowHandler after ending a flow in an ActionRequest.
			</para>
			<para>
				One way to start a 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, side effect may occur.
			</para>
			<para>
				JSF portlets are considered experimental at this time.
			</para>
		</sect2>
	</sect1>
</chapter>
