gamelan
Search EarthWeb
CodeGuru | Gamelan | Jars | Wireless | Discussions
Navigate developer.com
Architecture & Design  
Database  
Java
Languages & Tools
Microsoft & .NET
Open Source  
Project Management  
Security  
Techniques  
Voice  
Web Services  
Wireless/Mobile
XML  
Technology Jobs  

   Developer.com Webcasts:
  The Impact of Coding Standards and Code Reviews

  Project Management for the Developer

  Defining Your Own Software Development Methodology

  more Webcasts...




See the Winners!


Linked Data Planet Conference & Expo


Developer Jobs

Be a Commerce Partner
Computer Deals
Imprinted Gifts
Cell Phones
Baby Photo Contest
SMS Gateway
Holiday Gift Ideas
Disney World Tickets
Promotional Products
Send Text Messages
Promotional Pens
Boat Donations
Car Donations
Logo Design Custom
Prepaid Phone Card

 
Biz Resources
Network Security Services
VoIP
CRM Software


Storage Networking , Part 1
eBook: A storage network is any network that's designed to transport block-level storage protocols. But understanding the ins and outs of networked storage takes you deep into several of protocols. This guide covers SANs, Fibre Channels, Disk Arrays, Fabric, and IP Storage. »

Storage Networking 2, Configuration and Planning
eBook: Picking up where Part 1 left off, Part 2 of our look at storage networking examines configurations for SAN-attached servers and disk arrays, and also includes a look at the future of IP storage. »

Storage Management Costs in the Enterprise: A Comparison of Mid-Range Array Solutions
Whitepaper: Many factors contribute to the ownership cost for enterprise storage. These include (but are not limited to): physical capacity relative to physical space requirements, performance capacity for data transfer and system reaction time, software maintenance and updates, expandability and flexibility, and much more. »

Storage Is Changing Fast  Be Ready or Be Left Behind
PDF: The storage landscape is headed for dramatic change, thanks to new technologies like Fibre Channel over Ethernet (FCoE), pNFS, object-based storage and SAS that will affect everything from NAS and SANs to disk drives. Get the knowledge you need to make the most of your storage environment, now and in the future. »

HP StorageWorks EVA4400
Demo: Dont settle for an expensive and complex array that lacks functionality. The HP StorageWorks EVA4400 delivers virtual storage with enterprise class functionality at an affordable price. »

Developer News -
SaaS Tool Offers Custom Database Development    May 9, 2008
Microsoft’s Automated Agent: Can We Talk?    May 7, 2008
Borland Finally Sells CodeGear    May 7, 2008
Red Hat Heads For The JON 2.0    May 7, 2008
Free Tech Newsletter -

Best Practices for Developing a Web Site: Checklists, Tips, Strategies & More. Download Exclusive eBook Now.

Succeeding With Struts: Dynaforms
By James M. Turner

Once you've been using Struts for a while, you'll begin to notice that you spend a lot of time creating ActionForm classes. While these classes are critical to the MVC architecture of Struts (as they implement the view portion), they are usually simply a collection of bean properties and a validate method (also sometimes a reset method.)

With the Struts 1.1 release, developers have a new set of options to create their view objects, based around DynaBeans. DynaBeans are dynamically configured Java Beans, which means that they take their properties from some variety of external configuration (usually XML) rather than by explicit methods defined in the class.

To see how DynaBeans (and the Struts implementation, Dynaforms) work, let's begin with a simple Struts Form that records name, address, and telephone. Here's how it's currently implemented using ActionForm.

article1.CustomerForm

package article1;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionError;
import javax.servlet.http.HttpServletRequest;

public class CustomerForm extends ActionForm {

    protected boolean nullOrBlank (String str) {
        return ((str == null) || (str.length() == 0));
    }
    public  ActionErrors validate(ActionMapping mapping,
            HttpServletRequest request) {
        ActionErrors errors = new ActionErrors();
        if (nullOrBlank(lastName)) {
            errors.add("lastName",
                   new ActionError("article1.lastName.missing"));
        }
        if (nullOrBlank(firstName)) {
            errors.add("firstName",
                   new ActionError("article1.firstName.missing"));
        }
        if (nullOrBlank(street)) {
            errors.add("street",
                   new ActionError("article1.street.missing"));
        }
        if (nullOrBlank(city)) {
            errors.add("city",
                   new ActionError("article1.city.missing"));
        }
        if (nullOrBlank(state)) {
            errors.add("state",
                   new ActionError("article1.state.missing"));
        }
        if (nullOrBlank(postalCode)) {
            errors.add("postalCode",
                   new ActionError("article1.postalCode.missing"));
        }
        if (nullOrBlank(phone)) {
            errors.add("phone",
                   new ActionError("article1.phone.missing"));
        }
        return errors;
    }

    private String lastName;
    private String firstName;
    private String street;
    private String city;
    private String state;
    private String postalCode;
    private String phone;

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

As you can see, it's a standard JavaBean with the addition of the validate method, which makes sure that all the fields have been set up correctly.

The JSP page that interfaces with this bean is equally simple:

customer.jsp

<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<%@ taglib prefix="fmt" uri="/WEB-INF/fmt.tld" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<head>
<title>Example of a standard Customer form</title>
</head>
<h1>Example of a standard Customer form</h1>
<html:form action="/addCustomer">
Last Name: <html:text property="lastName"/>
<html:errors property="lastName" /><br>
First Name: <html:text property="firstName"/>
<html:errors property="firstName" /><br>
Street Addr: <html:text property="street"/>
<html:errors property="street" /><br>
City: <html:text property="city"/>
<html:errors property="city" /><br>
State: <html:text property="state" maxlength="2" size="2" />
<html:errors property="state" /><br>
Postal Code: <html:text property="postalCode" maxlength="5"
                                              size="5" />
<html:errors property="postalCode" /><br>
Telephone: <html:text property="phone" maxlength="11" size="11" />
<html:errors property="phone" /><br>
<html:submit/>
</html:form>

The Action for this page just sends the values to standard output (which will place them in the Catalina log file):

article1.AddCustomerAction

package article1;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionForm;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;

public class AddCustomerAction extends Action {
    public ActionForward execute(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
    throws ServletException, IOException{
        CustomerForm custForm = (CustomerForm) form;
        System.out.println("lastName   = "
                            + custForm.getLastName());
        System.out.println("firstName  = "
                            + custForm.getFirstName());
        System.out.println("street     = " + custForm.getStreet());
        System.out.println("city       = " + custForm.getCity());
        System.out.println("state      = " + custForm.getState());
        System.out.println("postalCode = "
                            + custForm.getPostalCode());
        System.out.println("phone      = " + custForm.getPhone());

        return mapping.findForward("success");
    }
}

This is all tied together, as always with Struts, in the struts-config.xml file:

<struts-config>
<form-beans>
<form-bean name="customerForm" type="jdj.article1.Customer" />
      </form-beans>
<action-mappings>
<action path="/addCustomer" type="article1.AddCustomerAction"
                            name="customerForm" scope="request"
                            input="/addCustomer.jsp">
<forward name="success" path="/addCustomerSucceeded.jsp"
                        redirect="false" />
</action>
</action-mappings>
<message-resources parameter="ApplicationResources" />
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property value="/WEB-INF/validator-rules.xml"
              property="pathnames" />
struts-config.xml</plug-in></struts-config>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC 
  "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
  "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
 <form-beans>
  <form-bean name="customerForm" type="article1.CustomerForm" />
 </form-beans>
 <action-mappings>
  <action path="/addCustomer" type="article1.AddCustomerAction"
          name="customerForm" scope="request" input="/customer.jsp">
      <forward name="success" path="/addCustomerSucceeded.jsp"
               redirect="false" />
  </action>
 </action-mappings>
 <message-resources parameter="ApplicationResources" />
 <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
   <set-property value="/WEB-INF/validator-rules.xml"
        property="pathnames" />
 </plug-in>
</struts-config>

The customerForm is linked to the CustomerForm class that was just defined, and the /addCustomer action is defined to use that form, and to use the article1.AddCustomerAction class to process the request.

When you bring up the form in your browser, you'll get a blank form ready to fill out:

Example of a Standard Customer Form

Last Name:
First Name:
Street Addr:
City:
State:
Postal Code:
Telephone:

If you submit the form with no values, you'll get the following screen:

Example of a Standard Customer Form

Last Name: Last Name is Required
First Name: First Name is Required
Street Addr: Street Name is Required
City: City Name is Required
State: State Name is Required
Postal Code: Postal Code Name is Required
Telephone: Phone Number Name is Required

And when you submit the form with filled-in values, the following will show up in your Web container log file (catalina.out under Tomcat):

lastName = Bush
firstName = George
street = 1600 Pennsylvania Avenue NW
city = Washington
state = DC
postalCode = 20500
phone = 2024561414

So far, this is vanilla Struts that everyone should be familiar with. But, by using some of the new features of Struts 1.1, you can drastically reduce the amount of code you need to write. For example, we can begin be using the Dynaform extension to eliminate the need for an ActionForm class. To do this, we change the definition of customerForm in the struts-config.xml to use the org.apache.struts.action.DynaActionForm class (for this tutorial, we'll actually create a new class and JSP page so that you can compare the two.)

By using DynaActionForm, you gain access to the form-property XML tag, which allows you to define the properties of a form directly in struts-config.xml . For our example, this looks like:

<form-bean name="dynaCustomerForm"
           type="org.apache.struts.action.DynaActionForm">
  <form-property name="lastName" type="java.lang.String"/>
  <form-property name="firstName" type="java.lang.String"/>
  <form-property type="java.lang.String" name="street"/>
  <form-property name="city" type="java.lang.String"/>
  <form-property name="state" type="java.lang.String"/>
  <form-property name="postalCode" type="java.lang.String"/>
</form-bean>

There are no changes that need to be made to the JSP file; the use of DynaForms is transparent to the Struts HTML tag libraries. You do need to make a slight change to the Action, however, because you can no longer cast the form passed in to the execute() method directly to a class with accessors (get and set methods) for your data. Instead, you need to cast the form to DynaActionForm and use the generic get(fieldname) accessors. So the new version of the Action looks like this:

article1.AddDynaCustomerAction

package article1;

import org.apache.struts.action.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;

public class AddDynaCustomerAction extends Action {
  public ActionForward execute(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
                       throws ServletException, IOException{
  DynaActionForm custForm = (DynaActionForm) form;
  System.out.println("lastName   = " + custForm.get("lastName"));
  System.out.println("firstName  = " + custForm.get("firstName"));
  System.out.println("street     = " + custForm.get("street"));
  System.out.println("city       = " + custForm.get("city"));
  System.out.println("state      = " + custForm.get("state"));
  System.out.println("postalCode = "
                      + custForm.get("postalCode"));
  System.out.println("phone      = " + custForm.get("phone"));

      return mapping.findForward("success");
     }
}

As you can see, this eliminates an entire class (the ActionForm). However, we've lost something else in addition, the ability to validate the form data. There are two ways to regain this ability. One is to create a class which subclasses DynaActionForm and implements a validate() method. In our current example, it would look something like this:

article1.DynaCustomerForm

package article1;

import org.apache.struts.action.*;

import javax.servlet.http.HttpServletRequest;

public class DynaCustomerForm extends DynaActionForm {

protected boolean nullOrBlank (String str) {
  return ((str == null) || (str.length() == 0));
 }

public ActionErrors validate(ActionMapping mapping,
                    HttpServletRequest request) {
  ActionErrors errors = new ActionErrors();
  if (nullOrBlank((String)this.get("lastName"))) {
    errors.add("lastName",
           new ActionError("article1.lastName.missing"));
  }
  if (nullOrBlank((String)this.get("firstName"))) {
    errors.add("firstName",
           new ActionError("article1.firstName.missing"));
  }
  if (nullOrBlank((String)this.get("street"))) {
    errors.add("street",
           new ActionError("article1.street.missing"));
  }
  if (nullOrBlank((String)this.get("city"))) {
    errors.add("city", new ActionError("article1.city.missing"));
  }
  if (nullOrBlank((String)this.get("state"))) {
    errors.add("state",
           new ActionError("article1.state.missing"));
  }
  if (nullOrBlank((String)this.get("postalCode"))) {
    errors.add("postalCode",
           new ActionError("article1.postalCode.missing"));
  }
  if (nullOrBlank((String)this.get("phone"))) {
    errors.add("phone", new ActionError("article1.phone.missing"));
  }
  return errors;
 }

}

Again, notice that we need to use the get() accessor rather than directly referencing instance variables. We also need to change the definition of the form in struts-config.xml to use this new class instead of the generic DynaActionForm class. When we do this, the validation functionality is returned, however; we're back to defining explicit classes for each form again. The recommended way to validate under Struts 1.1 is to use the Struts Validator Framework, which will be described in a future article.

In the next article in this series, we'll look at some more advanced uses of DynaForms. Specifically, we'll see how you can use indexed properties and arrays of beans to implement complex master-detail forms.

About the author

James Turner is the Director of Software Development for Benefit Systems, Inc. He is also a contributor to the Apache Struts project. He has two books out on web-facing Java technologies, MySQL and JSP Web Applications, and Struts Kick Start. His third book, Java Server Faces Kick Start, will be published by Sams in the 4th quarter of 2003.

Next article: Succeeding With Struts: Indexed Properties and Beans as Properties


Tools:
Add www.developer.com to your favorites
Add www.developer.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed


Web-based Java Archives

Work With InterSystems. Not Separate Systems. Rapidly develop and deploy connectable applications.
Generate Complete .NET Web Apps in Minutes . Download Iron Speed Designer today.
Learn about expanding business opportunities for the reseller channel. Visit IT Channel Planet.
Flash Demo: Learn how IBM Information Server Blade is easy to manage, highly scalable and efficient.
Developing Intelligent Communications? Visit the Avaya DevConnect Center on DevX.

IBM IT Innovation Resource Center:
WHITEPAPER:
An Architectural Blueprint for Autonomic Computing
ON DEMAND WEBCAST:
Blades Burst onto the Data Center Scene
BUSINESS VALUE ANALYZER:
IBM SOA Business Value Assessment
WHITEPAPER:
Tiered Information Infrastructure: A Practical Approach to Translating Strategy into Implementation


JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Solutions
Whitepapers and eBooks
Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
Microsoft Article: 7.0, Microsoft's Lucky Version?
Microsoft Article: Hyper-V--The Killer Feature in Windows Server 2008
Avaya Article: How to Feed Data into the Avaya Event Processor
Microsoft Article: Install What You Need with Windows Server 2008
HP eBook: Putting the Green into IT
Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
Avaya Article: Setting Up a SIP A/S Development Environment
IBM Article: How Cool Is Your Data Center?
Microsoft Article: Managing Virtual Machines with Microsoft System Center
HP eBook: Storage Networking , Part 1
Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
MORE WHITEPAPERS, EBOOKS, AND ARTICLES
Webcasts
Intel Video: Are Multi-core Processors Here to Stay?
On-Demand Webcast: Five Virtualization Trends to Watch
HP Video: Page Cost Calculator
Intel Video: APIs for Parallel Programming
HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
MORE WEBCASTS, PODCASTS, AND VIDEOS
Downloads and eKits
Sun Download: Solaris 8 Migration Assistant
Sybase Download: SQL Anywhere Developer Edition
Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
Red Gate Download: SQL Compare Pro 6
Iron Speed Designer Application Generator
MORE DOWNLOADS, EKITS, AND FREE TRIALS
Tutorials and Demos
How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
IBM Article: Collaborating in the High-Performance Workplace
HP Demo: StorageWorks EVA4400
Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
Microsoft How-to Article: Get Going with Silverlight and Windows Live
MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES