Attention: this page describes functionality that is not yet available! Work in progress!

Struts Component Lifecycle In Asynchronous Mode

If the browser has JavaScript turned on and the XMLHTTPRequest object is available, a web component is updated asynchronously; steps 1, 2 and 3 do not differ from synchronous mode:

  1. The cycle begins with the initial load of a composite page, starting the render phase. 2. When the JSP processor encounters a <c:import> action in a composite page, it generates an HTTP request to obtain the content of the included component. 3. The Action class forwards to a view relevant to component state. After all components on the composite page have rendered themselves, the render phase finishes and a composite page is presented to a user. 4. The user initiates the input phase by submitting an HTML form or by activating a command link. Javascript engine sends input data to the Action asynchronously using XMLHTTPRequest object. The Action processes data and updates component state if needed. Component state can be stored in a session-scoped form bean, in a database or in other location. 5. After input data has been processed, the Action forwards to a view relevant to component state. This view is returned to the browser in response to asynchronous request. The Javascript engine finds the spot in the composite page where the component resides, and updates page fragment in place. The user sees an updated page.

A Struts component incorporated into a page looks and behaves uniformly whether it runs in Ajax mode or not. The dual-mode functionality of Struts web components is invaluable for environments where JavaScript is not allowed or in browsers that do not support the XMLHTTPRequest object, like some mobile browsers.

It is worth noting that both Ajax and non-Ajax modes utilize the same code and markup.

Component Configuration

Same as for synchronous version.

Component Action

Same as for synchronous version. Event handlers should always return null, they cannot return an ActionForward object. It is not possible to forward or redirect to another page if request is sent in asynchronous mode.

Component Form Bean

Same as for synchronous version.

Login/Logout JSP page

The differences from synchronous version are:

  • content type must be set to "text/xml"
  • component markup must be valid XHTML
  • Content of JSP file must be wrapped into <comp:component> element
  • <html:form> and <html:input> elements must have styleClass attribute set to "strutsCommand", this enables runtime binding of Ajax functionality to these elements.
<%@ page contentType="text/xml;charset=UTF-8" language="java" %>

<%@ page import="java.util.ArrayList, org.apache.struts.Globals"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@ taglib uri="http://struts.apache.org/tags-comp" prefix="comp" %>

<comp:component>

<%-- "Not Logged In" subview --%>

<c:if test='${empty USER}'>
  <h3>Please Log In</h3>

  <!-- Displaying Struts errors -->
  <logic:messagesPresent>
    <html:messages id="error">
      <li><bean:write name="error"/></li>
    </html:messages>
  </logic:messagesPresent><br/>

  <%-- "strutsCommand" CSS class is a hook for Ajax-mode handler, it is set
       in runtime using Behaviour library. --%>

  <html:form method="get" styleClass="strutsCommand" action="/loginintegrated.do">
    <label for="username">Username:</label>
    <input type="text" name="username" value="${loginform.username}" class="datavalue"/><br/>

    <label for="password">Password:</label>
    <input type="text" name="password" value="" class="datavalue"/><br/>

    <input type="submit" name="loginEvent" value="Log In" class="strutsCommand"/>
  </html:form>
  <p><em>Username is "guest", password is "pass".</em></p>
</c:if>

<%-- "Logged In" subview --%>

<c:if test='${not empty USER}'>
  <h3>User Information</h3>

  <html:form method="post" styleClass="strutsCommand" action="/loginintegrated.do">
    <label>Current user:</label>
    <div class="datavalue">${USER}</div><br/>
    <input type="submit" name="logoutEvent" value="Log Out" class="strutsCommand"/><br/>
  </html:form>
</c:if>

</comp:component>

Composite Page

The differences from synchronous version are:

  • <c:import> that includes a component, must be wrapped into a DIV or another element with ID equal to component name. This ensures that component markup is properly updated in-place.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-comp" prefix="comp" %>

<html>
  <body>
    <p>This paragraph is defined directly in the parent page
    and should precede the content of login control.</p>

    <%-- The login component, notice that DIV has the same ID as
         the component's name --%>
    <div id="Login">
      <c:import url="/loginintegrated.do" />
    </div>

    <p>This paragraph is defined directly in the parent page
    and should follow the content of login control.</p>
  </body>
</html>

Done!

Now you can develop independent Struts components!

  • No labels