Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Struts Wiki" for change 
notification.

The following page has been changed by MichaelJouravlev:
http://wiki.apache.org/struts/StrutsManualActionWebComponent

------------------------------------------------------------------------------
  ## page was renamed from StrutsComponents
  #format wiki
  #language en
+ 
+ '''Attention: this page describes functionality that is not yet available! 
Work in progress!'''
  
  Struts 1.4 allows building portlet-like web components using JSP as view 
technology. ''Struts web component'' is an independent server-side object that 
accepts user input via Action class, and renders itself via JSP file. In a 
sense, Struts web component is a portlet.
  
@@ -21, +23 @@

     * Updates page incrementally without full page refresh if browser has 
Javascript turned on and XMLHTTPRequest is available.
     * Seamlessly integrates with Struts, enhancing a well-known action 
framework with component technology.
  
- == Struts Component Lifecycle In Synchronous Mode ==
- 
- In synchronous mode the component lifecycle is managed in a five-step process:
- 
-    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. The browser sends input data to an Action that 
manages component events and state. 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 automatically redirects 
to location of the composite page, effectively switching from input phase back 
to render phase. Steps 1 through 3 are repeated, and an updated page is 
presented to the user.
- 
- inline:action_component_title.gif
- 
- == 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.
- 
- inline:action_component_ajax_title.gif
- 
- 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.
- 
  == Use Case: Home Page With Login Component ==
  
  Consider the following use case: a website has a home page that should have 
different content for regular visitors one one hand, and for logged in users 
for another hand. The page contains login/logout form. A non-logged-in user 
must be presented with login, while a logged-in user should be able to log out.
@@ -57, +31 @@

  
  inline:login-component-sm.gif
  
- = Building A Synchronous Component with Struts 1.4 =
+ == Building Struts Web Components ==
  
- The first exercise is building a synchronous, non-Ajax component. It is 
simpler than Ajax component because we do not need to fiddle with Javascript. 
On the other hand, it is more complex because instead of simply replacing one 
piece of page with another we need to figure out the location of original 
composite page and then to redirect to that location in order to reload the 
whole page.
+ See the links below for further reading:
  
- == Component Configuration ==
+  * [:StrutsManualActionWebComponentSync:Building synchronous Struts web 
component]
+  * [:StrutsManualActionWebComponentAsync:Building dual-mode Struts web 
component]
  
- First let us define the Login Component in {{{struts-config.xml}}} file:
- 
- {{{
- <struts-config>
- 
-   <form-beans>
-     <!-- Login form -->
-     <form-bean name = "loginform" type="samples.login.LoginForm"/>
-   </form-beans>
- 
-   <action-mappings>
- 
-       <!-- Composite page containing login component -->
-       <action path="/login-struts"
-               forward="/login-struts/index.jsp"/>
- 
-       <!-- Login component -->
-       <action component = "Login"
-               view = "/login-struts/loginComponent.jsp"
-               path = "/logincomponent"
-               type = "samples.login.LoginAction"
-               form = "loginform"
-               scope = "session"
-               validate  = "false">
-           <event name="loginEvent" handler="login"/>
-           <event name="logoutEvent" handler="logout"/>
-       </action>
- 
-   </action-mappings>
- </struts-config>
- }}}
- 
- Notice action mapping attributes and properties that are new for Struts 1.4:
- 
-    * "component" attribute identifies an action as a component manager, such 
actions are processed differently by Action class. This name is also used in 
generated HTML for in-place update in Ajax mode.
-    * "view" attribute identifies a default view for a component. Must be a 
JSP page. Often consists from several subviews, in our case the Login Component 
has two subviews "Not Logged In" and "Logged In", they will be defined in JSP 
file.
-    * "form" is just another name for "name" property
-    * "event" property allows to define request parameters as events, and 
corresponding method handlers. This is made possible by supporting dispatching 
functionality directly in Action class.
- 
- == Component Action ==
- 
- The action class is deceptively simple. It handles only two events, the 
corresponding handlers are called automatically by Action class. The location 
of component's view is defined in the action mapping, so render method is not 
needed. On the other hand, most non-trivial components need to process data 
before rendering themselves or to exchange data with other components. For 
these cases you can use render" method. Its default implementation does nothing.
- 
- {{{
- public class LoginAction extends Action {
- 
-     public ActionForward login (ActionMapping mapping,
-                                 ActionForm form,
-                                 HttpServletRequest request,
-                                 HttpServletResponse response) throws 
Exception {
- 
-         HttpSession session = request.getSession();
-         LoginForm inputForm = (LoginForm) form;
- 
-         // Log out current user first
-         request.getSession().removeAttribute("USER");
- 
-         // Validation is turned off in struts-config.xml,
-         // so explicitly validate user input;
-         ActionMessages errors = inputForm.validate(mapping, request);
- 
-         if (errors != null) {
-             saveErrors(session, errors);
-         } else {
-             // Use this session attribute to hold user's name
-             session.setAttribute("USER", inputForm.getUsername());
-         }
- 
-         // Always return null.
-         return null;
-     }
- 
-     public ActionForward logout (ActionMapping mapping,
-                                  ActionForm form,
-                                  HttpServletRequest request,
-                                  HttpServletResponse response) throws 
Exception {
- 
-         LoginForm inputForm = (LoginForm) form;
- 
-         // Clean name and password in the input/output form bean
-         inputForm.setUsername(null);
-         inputForm.setPassword(null);
- 
-         // Remove dialog name from session, effectively logging out
-         request.getSession().removeAttribute("USER");
- 
-         // Always return null.
-         return null;
-     }
- }
- }}}
- 
- == Component Form Bean ==
- 
- Nothing exciting here, just a session-scoped form to hold user name and to 
validate credentials:
- 
- {{{
- public class LoginForm extends ActionForm {
- 
-     private String username;
-     public String getUsername() {return username;}
-     public void setUsername(String username) {this.username = username;}
- 
-     private String password;
-     public String getPassword() {return password;}
-     public void setPassword(String password) {this.password = password;}
- 
-     // Generate the error messages in the same manner as usual,
-     // but do not forget to turn "validate" property of the action mapping 
off.
-     public ActionErrors validate(ActionMapping mapping, HttpServletRequest 
request) {
-         if (!"guest".equalsIgnoreCase(username) ||
-             !"pass".equalsIgnoreCase(password)) {
-             ActionErrors errors = new ActionErrors();
-             errors.add("ERROR", new ActionMessage("login.badpassword"));
-             return errors;
-         } else {
-             return null;
-         }
-     }
- }
- }}}
- 
- == Login/Logout JSP page ==
- 
- The Login/Logout component has two subviews, both defined in one JSP page. 
Notice that content type is set to "text/xml", this is important for Ajax mode.
- 
- {{{
- <%@ 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 ==
- 
- Now we need to include the Login Component into a larger page (composite 
page). This is done with JSTL c:import tag. Do not use jsp:include, it may not 
work on some containers:
- 
- {{{
- <%@ 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! ==
- 
- This is pretty much it. Now run the application and navigate to composite 
page. The included component will evaluate user's state and will display a 
login form. Try to log in. The submitted credentials are sent directly to a 
component, if they are not correct, the composite page is redisplayed. How? 
Behind the scenes the improved Action class as well as JSP tags work together 
to distinguish the address of a composite page during first render. This 
address is saved automatically. Then after component finishes, it reloads the 
composite page using saved address. Now you can develop independent Struts 
components!
- 
- 
- = Building An Asynchronous Component with Struts 1.4 =
- 
- Next installment: making components that update themselves in place without 
full page reload (Ajax mode).
- 
- == Download ==
- 
- Download and run thjis application: attachment:struts-components.war (Use JSP 
2.0 container like Tomcat 5)
- 

Reply via email to