<?xml version="1.0"?>
<!--
Copyright 2004 The Apache Software Foundation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
  <properties>
    <title>Struts Bridge Features</title>
    <subtitle></subtitle>
    <authors>
      <person name="Ate Douma" email="ate@douma.nu"/>
    </authors>
  </properties>
  <body>
    <section name="Features">
      <p>
        The Struts Bridge provides the following features for developing and running Struts Applications as Portlets:
        <ul>
          <li>
            <a href="#Struts Page URL">
              Provides a "virtual" page context and a "normal" page url to the Struts Application
            </a>
          </li>
          <li>
            <a href="#The ServletContextProvider interface">
              Allows Servlet invocation from an ActionRequest using an separate lightweight interface to the Portal
            </a>
          </li>
          <li>
            <a href="#Portals requiring a more complex interface">
              Provides extension points if a more complex interface to the Portal is required
            </a>
          </li>
          <li>
            <a href="#Handling ActionRequests">
              Automatically separates Struts Action Processing and View Rendering when accessed from an ActionRequest
            </a>
          </li>
          <li>
            <a href="#RenderContextAttributes to the rescue">
              Transparent communication of request attributes between ActionRequest and RenderRequests
            </a>
          </li>
          <li>
            <a href="#Rendering valid Portlet urls with the Struts JSP Tags">
              Transparent translation of "normal" Web application resource and action link urls to valid Portlet urls
            </a>
          </li>
          <li>
            <a href="#PortletRequestProcessor and PortletTilesRequestProcessor">
              Tiles support and automatic configuration of the correct (Portlet)RequestProcessor 
            </a>
          </li>
          <li>
            <a href="#Running your application as Portlet and Web Application at the same time">
              Deploy and run Struts Applications as Portlet and as Web Application at the same time
            </a>
          </li>
          <li>
            Based on the latest official Struts release 1.2.4
          </li>
        </ul>
      </p>
      <subsection name="Struts Page URL">
        <p>
          Struts determines the Actions to perform on the request url. A Portlet on the other hand doesn't
          have or receive an url, only request parameters.
        </p>
        <p>
          To be able to use Struts within a Portlet, a current Page context is maintained by the Struts Bridge
          which is used to provide Struts with a "virtual" request context just as if it were accessed from a Web
          Application.
        </p>
        <p>
          The Struts Page URL is maintained as a Portlet <code>RenderParameter</code> and included in all Portlet URLs
          generated for the Portlet. When the <code>StrutsPortlet</code> receives a request it uses the Struts Page URL
          to create a new <code>HttpServletRequest</code> with a redefined request url before invoking the Struts
          <code>PortletServlet</code> (extending the Struts <code>ActionServlet</code>). 
        </p>
        <p>
          None of the Action Mappings for an existing Struts Application have to be changed (in this respect at least)
          to allow it to run in a Portlet context. 
        </p>
      </subsection>      
      <subsection name="The ServletContextProvider interface">
        <p>
          Processing <code>ActionRequest</code> and <code>RenderRequest</code> events from a Servlet application is a
          problem with the current Portlet Specification. Although Servlets (and JSPs) can be invoked from a Portlet,
          the Portlet Specification only supports this from the <code>RenderRequest</code>.
        </p>
        <p>
          As request parameters are only available during the <code>ActionRequest</code>, not being able to use a Struts
          for processing these is a serious limitation. Together with no clear inter-portlet application communication
          support, this is probably one of the biggest omisions from the Portlet Specification.
        </p>
        <p>
          But, because the Portlet Specification is build upon the Servlet Specification (2.3), the Portlet Container
          implementation (like <a href="http://portals.apache.org/pluto">Pluto</a>) and/or the Portal itself, usually
          does have direct access to, and also uses the <code>ServletContext</code>, even during the
          <code>ActionRequest</code> event.           
        </p>
        <p>
          It is therefore usually very easy to provide access to the <code>ServletContext</code> although it will
          require knowledge about the concrete implementation of the Portal and/or the Portlet Container.
        </p>
        <p>
          The Struts Bridge uses the <code>ServletContextProvider</code> interface from the Portals Bridges Common
          portals-bridges-common library, to get access to the <code>ServletContext</code> it requires.
       </p>
        <p>
          To be able to use the Struts Bridge, a <code>StrutsPortlet</code> must be provided with a concrete
          implementation of the <code>ServletContextProvider</code> interface (through its initialization parameters).
          This implementation class can be supplied together with the Portlet or be provided natively by the Portal as
          the <a href="http://portals.apache.org/jetspeed-2">Jetspeed-2</a> Portal does. 
        </p>
      </subsection>      
      <subsection name="Portals requiring a more complex interface">
        <p>
          Although the <code>ServletContextProvider</code> interface has been defined to be easily implemented for a
          specific Portal, it might not be generic enough for all.
        </p>
        <p>
          To support those kind of Portals, the <code>StrutsPortlet</code> doesn't uses the interface directly, but only
          through protected methods of its own which can be extended if needed.
        </p>
      </subsection>      
      <subsection name="Handling ActionRequests">
        <p>
          During an <code>ActionRequest</code> a Portlet (or invoked Servlet) is not allowed to write content to the
          response. This is only allowed during the <code>RenderRequest</code> event, but then a Portlet doesn't have
          access anymore to the (input) request parameters which makes it generally useless (and bad practice anyway)
          for (Struts) Action processing.
        </p>
        <p>
          Struts on the other hand only knows one request event and is largely build upon server-side forwarding to a
          JSP (or other View rendering technology) after an Action has been processed.
        </p>
        <p>
          The Struts Bridge solves this problem by allowing Struts Action processing to occur during the ActionRequest.
          But, as soon as Struts forwards (or includes) to another handler (JSP, Velocity script, <em>or even another
          Action></em>) it will intercept and freeze the processing.<br/>
          The Struts Bridge will then save the current processing context (like the path to include or forward to) in a
          separate object, the <code>StrutsRenderContext</code>, and end the ActionRequest.<br/>
          Once the RenderRequest is invoked, the Struts Bridge will use the <code>StrutsRenderContext</code> to restore
          the state Struts (and/or an included or forwarded JSP) will expect and continues the processing where it left
          off.
        </p>
        <p>
          Also saved in the StrutsRenderContext are the current <code>ActionForm</code> (if it isn't already session
          bounded), the <code>ActionMessages</code> and/or <code>ActionErrors</code> (if not already session bounded
          which is possible since Struts 1.2.1).
        </p>
        <p>
          <b><em>Important:</em></b> the StrutsRenderContext is restored only once!
        </p>
        <p>
          The Portlet Specification expects Portlets to use a true MVC architecture: changing the state of a Portlet is
          expected to be done during ActionRequest only. The RenderRequest, which may occur many times, is expected to
          to only render the current state of the Portlet.
        </p>
        <p>
          For a proper usage of the Struts Bridge and to conform to the Portlet Specification requirements, the Struts
          application too really should be configured to use separate Action processing and View rendering Actions.<br/>
        </p>
        <p>
          The dependency on the StrutsRenderContext restoring the state during the (next) RenderRequest should be
          limited to one situation only: input error processing.
        </p>
        <p>
          When Struts encounters input validation errors, it forwards (back) to the page specified as input for the
          Action. The Struts Bridge handles this situation likewise. When it detects ActionErrors are defined after the
          ActionRequest event, it will reset the Struts Page URL to the one from which the ActionRequest was initiated
          StrutsRenderContext so subsequent (multiple) RenderRequest events will always render that input page.
        </p>
        <p>
          Note: this will only result the same behavior as when the Struts Application is accessed as Web Application if
          the Action Mapping input attribute indeed points to the originating input page, which normally will be the
          case.
        </p>
        <p>
          As said, for a proper usage of the Struts Bridge, the Struts application should be configured to use separate
          Action processing and View processing Actions. The Struts Bridge intercepts the first include or forward 
          initiated from a Struts Action during the ActionRequest. During only the first following RenderRequest it will
          invoke Struts with <em>the same Struts Page URL</em> as for the ActionRequest but intercept before the actual
          execution of the mapped Action and then include (never forward) the intercepted target url of the ActionRequest
          (normally a JSP).          
        </p>
        <p>
          A properly MVC configured Struts application though can (and should) make use of a (client-side) redirect
          after the Action processing Action by using an ActionForward with redirect="true". The behavior of such an
          Struts Application then truly complies to the requirements for a Portlet. In fact, the reference
          implementation of the Portlet Specification, <a href="http://portals.apache.org/pluto">Pluto</a>, actually
          sends a redirect to the client (browser) after an ActionRequest.
        </p>
        <p>
          The Struts Bridge supports this behavior as it will intercept a client-side redirect during an ActionRequest
          by changing the Portlet Page URL to be used by subsequent RenderRequests to the targeted redirect url.
        </p>
        <p>
          A Struts Application not complying to the above "rules" might not behave as expected in a Portlet context:<br/>
          without this configuration a second RenderRequest event will not get the previously saved StrutsRenderContext
          restored and the invoked Struts Action will be executed again (this time without any parameters).
        </p>
        <p>
          Migrating an existing Struts Application to a Struts Portlet with doesn't comply to these "rules" might seem
          problematic without major changes to the code, but it doesn't have to be. 
        </p>
      </subsection>      
      <subsection name="RenderContextAttributes to the rescue">
        <p>
          Although a StrutsRenderContext can only be used once to communicate request parameters from the ActionRequest
          to the next RenderRequest (stored in the ActionForm), the Struts Bridge provides another, completely
          transparent, solution which can be used without any required changes to the Struts Application.
        </p>
        <p>
          The Struts Bridge can be configured, using a simple xml definition, to always save specific named request
          attributes during an ActionRequest and restore these only during the next RenderRequest or optionally every
          RenderRequest until the next ActionRequest or a RenderRequest for a different Struts Page URL is invoked.
        </p>
        <p>
          The request attribute values will be saved in the web session which requires them to implement the
          <code>Serializable</code> interface.
        </p>
        <p>
          An example struts-portlet-config.xml (the name of this file is configurable) definition might look like:
          <source><![CDATA[
            <?xml version="1.0" encoding="UTF-8"?>
            <config>
              <render-context>
                <attribute name="errors"/>
                <attribute name="message" keep="true"/>
              </render-context>
            </config>]]></source>
          <em>(This (adapted) example is taken from the JPetstore Portlet example provided with the
          <a href="http://portals.apache.org/jetspeed-2">Jetspeed-2</a> Portal.)</em>           
        </p>
        <p>
          With the above example configuration, all request attributes named errors and message are saved after the
          ActionRequest. The errors object is restored only once, the message object will be restored until the next
          ActionRequest or when the Struts Page URL is changed. 
        </p>
        <p>
          Using the RenderContextAttributes configuration, a Struts Action can still forward (without redirecting) to a
          JSP in a Portlet while passing its required data through the request attributes. Request scoped ActionForms
          can also safely be used for this as the Struts Bridge will automatically removes them from the session again
          when they go out of scope!      
        </p>
        <p>
          Using the single use only configuration (without the keep="true" attribute) allows one to pass on rather large
          objects to the RenderRequest because, even if they are stored in the Session, this will only be for a very
          short period (milliseconds). Of course, with a subsequent RenderRequest these objects won't be available
          anymore and the specific View Renderer must be defined to handle that situation properly.<br/>
          Error objects or error messages (other than ActionMessages and ActionErrors which are already automatically
          saved in the StrutsRenderContext) are also reasonable candidates to use like this.
        </p>
      </subsection>      
      <subsection name="Rendering valid Portlet urls with the Struts JSP Tags">
        <p>
          Another problem with using Struts for Portlet Development is rendering valid urls.
        </p>
        <p>
          There are actually two different type of problems: urls for resources likes images, Javascript or CSS
          stylesheets which needs to be loaded by the client (browser), and urls for interacting with the Portlet
          itself.
        </p>
        <p>
          The problem with resource urls is the fact that the content of a Portlet is only included by the Portal,
          together with possible content of other Portlets shown on the same page. Although the Portlet runs within
          its own context (the same as the web application it is based on), the client (browser) sees only the context
          of the Portal page it is currently pointed at.
        </p>
        <p>
          A Portlet therefore cannot make use of relative src locations for a resource url while this is perfectly valid
          (mostly usually preferred) in a Web Application. For a client to be able to retrieve a resource, its url
          really must include the full context path of the Web Application.
        </p>
        <p>
          For interacting with the Portlet special PortletURLs must be used which can only be generated using the
          Portlet API or through the Portlet JSP Tags. The Struts JSP Tags only generate urls valid for a Web
          Application and also doesn't provide some kind of URLProvider interface like JSF.
        </p>
        <p>
          Furthermore there are two different PortletURL types: an ActionURL and a RenderURL.
          It is very important to generate the correct type of url for a certain interaction. Forms must *always* use
          a POST to an ActionURL, but for all generated links it will have to be determined which type of url actually
          is required. 
        </p>
        <p>
          To solve these problems, the Struts Bridge provides enhanced versions of the Struts HTML JSP Tags (including
          EL variants), which take the Portlet environment into account. Furthermore, using a separate element in
          the struts-portlet-config.xml definition, specific url paths can be configured to be of a certain type
          (Resource, ActionURL, RenderURL) only.
        </p>
        <p>
          For the enhanced Struts HTML JSP Tags (html:form, html:link, html:rewrite, html:image and html:img), four
          different TLDs are provided: a EL and non-EL variant, and for both a full replacement of the Struts
          supplied struts-html.tld as well as a separate struts-portlet.tld containing only the enhanced Tags definitions.  
        </p>
        <p>
          The full replacement TLDs makes it very easy for migrating a Struts Application to a Portlet context: simply
          map the new TLD in web.xml or redefine the taglib uri in the JSP using:
          <source><![CDATA[
            <%@ taglib uri="http://portals.apache.org/bridges/struts/tags-portlet-html" prefix="html" %>]]></source>
          or
          <source><![CDATA[
            <%@ taglib uri="http://portals.apache.org/bridges/struts/tags-portlet-html-el" prefix="html-el" %>]]></source>
            <em>(Note: the Struts Bridge library contains all the TLDs so you don't need to add them yourself 
            somewhere under WEB-INF/.)</em>
        </p>
        <p>
          For the enhanced html:link and html:rewrite Tags, three additional boolean attributes are defined: actionURL,
          renderURL and resourceURL. Using these attributes one can specify which type of url must be generated (only
          value "true" is supported).
        </p>
        <p>
          If non of these attributes is specified (with value "true") these Tags will by default generate a RenderURL.          
        </p>
        <p>
          But, the default can be changed (only between renderURL and actionURL) using the struts-portlet-config.xml
          definition. Furthermore, for specific url path (prefixes) you can specify which type of url must be generated
          (specifying one of the three url type attributes will always override though).
        </p>
        <p>
          An example struts-portlet-config.xml with portlet url type definitions might look like:
          <source><![CDATA[
            <?xml version="1.0" encoding="UTF-8"?>
            <config>
              <render-context>
                <attribute name="errors"/>
                <attribute name="message" keep="true"/>
              </render-context>
              <portlet-url-type>
                <action path="/shop/add"/>
                <action path="/shop/switch"/>
                <action path="/shop/remove"/>
                <action path="/shop/signoff"/>
                <action path="/shop/viewCategory"/>
                <action path="/shop/viewItem"/>
                <action path="/shop/viewProduct"/>
                <action path="/shop/viewCart"/>
                <action path="/shop/newOrder"/>
                <render path="/shop/newOrderForm"/>
                <action path="/shop/listOrders"/>
                <resource path="/images/"/>
              </portlet-url-type>
            </config>]]></source>
          <em>(This is the full configuration used for the JPetstore Portlet example provided with the
          <a href="http://portals.apache.org/jetspeed-2">Jetspeed-2</a> Portal.)</em>           
        </p>
        <p>
          In the above example the portlet-url-type element contains three different sub elements: action, render and
          resource. Their path attribute specifies the prefix to which specific urls are matched. This matching will be
          done using best match. Internally, the paths will be ordered on longest definition first.
        </p>
        <p>
          Not shown in the above example is the optional default="render"|"action" attribute for the portlet-url-type
          element. With it, the default type of portlet-url can be changed from "render" to "action" as is used in the
          Struts Mailreader Demo Portlet (also provided by the <a href="http://portals.apache.org/jetspeed-2">Jetspeed-2</a>
          Portal):
          <source><![CDATA[
            <?xml version="1.0" encoding="UTF-8"?>
            <config>
              <portlet-url-type/>
            </config>]]></source>
            This feature is especially useful for Struts Applications who were configured using an earlier version of
            the Struts Bridge (0.1) which used an ActionURL as default, like the above Struts Mailreader Demo Portlet.
        </p>
        <p>
          The enhanced html:img and html:image Tags, as well as the html:link and html:rewrite Tags, can be used to
          generate resource urls using relative (not prefixed with a '/') src references. The Tags will then determine
          automatically determine the correct url to generate using the current Struts Page URL as defined for this
          RenderRequest.
        </p>
        <p>
          This allows one to replace hard coded resource urls like 
          <source><![CDATA[<img src="../images/struts-bridge.gif"/>]]></source>
          with  
          <source><![CDATA[<html:image src="../images/struts-bridge.gif"/>]]></source>
          A simple change with no technical impact, but it will allow the same JSP to be used for both a Web Application
          and a Portlet. The JPetstore Portlet example as provided by <a href="http://portals.apache.org/jetspeed-2">Jetspeed-2</a>
          makes full use of this feature.
        </p>
      </subsection>      
      <subsection name="PortletRequestProcessor and PortletTilesRequestProcessor">
        <p>
          The Struts Bridge requires a different RequestProcessor to be used for the Struts Application: a <code>
          PortletRequestProcessor</code>. If a Struts config doesn't define one, or defines one which isn't based on the
          PortletRequestProcessor, it will be replaced automatically by the Struts Bridge.
        </p>
        <p>
          The Struts Bridge also supports Tiles to be used through its <code>PortletTilesRequestProcessor</code>. If the
          TilesPlugin is defined (as required to be able to use Tiles in Struts) it will be recognized by the Struts
          Bridge and then the PortletTilesRequestProcessor will be used instead (if not configured already).          
        </p>
        <p>
          Tiles can be used without problem within a Portlet context, even for Action Mapping or ActionForward paths,
          although the same considerations and restrictions must be taken into account as described above.
        </p>
      </subsection>      
      <subsection name="Running your application as Portlet and Web Application at the same time">
        <p>
          Although the Struts Bridge is created to allow Struts Applications to run in a Portlet context, it also allows
          the same application to be run in a Servlet context too.
        </p>
        <p>
          If the Struts Bridge PortletServlet (which extends ActionServlet) detects it is not accessed from a Portlet
          context is simply delegates back to the underlying Struts Framework.
        </p>
        <p>
          Provided the Struts Application doesn't use any Portlet specific features and the Action Mapping configuration
          is also (still) valid for a Web Application, the same application war can be deployed as Web application and
          as Portlet Application. When deployed in a Portal, the application can even be accessed as Portlet or as 
          Web Application at the same time!
        </p>
        <p>
          The JPetstore Portlet example provided by <a href="http://portals.apache.org/jetspeed-2">Jetspeed-2</a> is one
          example of such a "dual" mode Struts Application.
        </p>
        <p>
          Another benefit of such a "dual" mode Struts Application is that it can be fully tested as Web Application, 
          which <em>is</em> somewhat easier than testing it as a Portlet.
        </p>
      </subsection>      
    </section>
  </body>
</document>