Archive

Archive for the ‘Articles’ Category

Wicket Component Tour: Enclosure

July 3rd, 2007

The next Wicket component presented in our series is the Enclosure component. Enclosure doesn’t have a direct comparison with other frameworks, but it’s a very useful component.

Click here for the full article

nick Articles, Entry

Wicket Component Tour: RadioGroup

May 7th, 2007

The next component in the Wicket Component series is the RadioGroup. This is component isn’t exactly obvious, especially if you’re new to Wicket.

Click here for the full article

nick Articles, Entry

Wicket Component Tour: DropDownChoice

May 3rd, 2007

Coming from a Struts background, select lists were always incredibly painful to deal with. The first in a new series of posts on Wicket components presents a more elegant way to deal with select lists from the Wicket perspective: DropDownChoice.

Click here for the full article

nick Articles, Entry

Creating and Validating Struts DynaForms with XDoclet

August 9th, 2006

The XDoclet Struts module supports creating and validating DynaForms through the use of a handful of XDoclet JavaDoc tags. It’s pretty simple, but some explanation is required to take full advantage of this feature. This short tutorial is mostly code, without much description of the various XDoclet tags you’ll see here. For a detailed description, please refer to the XDoclet site.

Let’s start out by looking at two separate classes, Person and Address. Person is shown first:


/**
* @struts.dynaform name="personForm"
* type="org.apache.struts.validator.DynaValidatorActionForm"
* validate="true"
*/
public class Person {
private Long id;
private String name;
private String notes;
private Address address;
public void setId(Long id) { this.id = id; }
public Long getId() { return this.id; }
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="person.name"
*/
public void setName(String name) { this.name = name; }
/**
* @struts.dynaform-field
*/
public String getName() { return this.name; }
/**
* @struts.validator
*/
public void setAddress(Address address) { this.address = address; }
/**
* @struts.dynaform-field
*/
public Address getAddress() { return this.address; }
/**
* @struts.validator type="maxlength"
* @struts.validator-args arg0resource="person.notes"
* @struts.validator-args arg1value="${var:maxlength}"
* @struts.validator-var name="maxlength" value="4000"
*/
public void setNotes(String notes) { this.notes = notes; }
/**
* @struts.dynaform-field
*/
public String getNotes() { return this.notes; }
}

As you can see, Person is pretty simple - just a few properties and some comments. The associated Address class is shown below:


public class Address {
private String line1;
private String line2;
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line1"
*/
public void setLine1(String line1) { this.line1 = line1; }
public String getLine1() { return this.line1; }
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line2"
*/
public void setLine2(String line2) { this.line2 = line2; }
public String getLine2() { return this.line2; }
}

Now that we have our two classes, let’s go over the various tags and what each one does, starting with the Person class.


/**
* @struts.dynaform name="personForm"
* type="org.apache.struts.validator.DynaValidatorActionForm"
* validate="true"
*/
public class Person {

The class-level XDoclet tags define that a DynaValidatorActionForm should be created in the struts-config.xml file, with a name of “personForm” and a type of “org.apache.struts.validator.DynaValidatorActionForm”. You can substitute your own type here if you want to subclass one of the ActionForm classes. If you want to also generate the validation rules for your DynaForm, you have to include the ‘validate=”true”‘ attribute. This attribute just aids processing by the XDoclet templates; it’s not included in the output files. After the class-level comments, we have the various method-level comments. We’ll start with the name attribute in the Person class.


/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="person.name"
*/
public void setName(String name) { this.name = name; }
/**
* @struts.dynaform-field
*/
public String getName() { return this.name; }

The above code is a simple setter and getter pair. What makes this attribute interesting are the comments that generate the valication rules and the form property. Starting with the setter, we can see that the name property is required when the user submits the DynaForm. If the name property is omitted, the “person.name” value is retrieved from the resource bundle. It’s probably best to look at the generated portion of the validation.xml file to understand what’s going on here:


<form name="personForm">
<field
property="name"
depends="required">
<arg0
key="person.name"
/>
</field>
...
</form>

As you can see, it’s pretty simple to define the validation rules use XDoclet tags. Of course, we also need to define our form fields. The getter method has the relevant XDoclet tag to create a form-property element in our struts-config.xml. As shown, the struts.dynaform-field tag will just create the following XML snippet:


<form-property name="name" type="java.lang.String"/>

The name and type attributes are taken from the method. Of course, we don’t have to use the defaults. We can specify a different name and type if we want, as well as define multiple form fields in the getter. For example:


/**
* @struts.dynaform-field
* name="firstName"
* type="java.lang.String"
* @struts.dynaform-field
* name="lastName"
* type="java.lang.String"
*/
public String getName() { return this.name; }

This feature is handy when you need to add additional form fields, but don’t need to define additional object attributes. Let’s look at what our complete form definition for the struts-config.xml would look like:


<form-bean name="personForm" type="org.apache.struts.validator.DynaValidatorActionForm">
<form-property name="name" type="java.lang.String"/>
<form-property name="address" type="example.Address"/>
<form-property name="notes" type="java.lang.String"/>
</form-bean>

What about that Address class? We haven’t talked about it yet. We’re not concerned about creating a DynaForm representation of it, although we could rather easily. Instead, the personForm will just have an instance of the Address class and will access it as a nested bean. We’re more concerned about validating the properties of the Address class when the user submits a personForm. Let’s revisit the Address property in the Person class:


/**
* @struts.validator
*/
public void setAddress(Address address) { this.address = address; }
/**
* @struts.dynaform-field
*/
public Address getAddress() { return this.address; }

You can see that the setter for the Address only has a simple struts.validator tag. That tells the XDoclet template to look in the Address class for all of the validation definitions:


/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line1"
*/
public void setLine1(String line1) { this.line1 = line1; }
...
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line2"
*/
public void setLine2(String line2) { this.line2 = line2; }

The XDoclet template follows the struts.validator rule in the Person class to the Address class and includes whatever it finds there. The final result of these rules is the following validation.xml snippet for the personForm:


<form name="personForm">
<field
property="name"
depends="required">
<arg0
key="person.name"
/>
</field>

<field
property="notes"
depends="maxlength">
<arg0
key="person.notes"
/>
<arg1
key="${var:maxlength}"
resource="false"
/>
<var>
<var-name>maxlength</var-name>
<var-value>4000</var-value>
</var>
</field>

<field
property="address.line1"
depends="required">
<arg0
key="address.line1"
/>
</field>

<field
property="address.line2"
depends="required">
<arg0
key="address.line2"
/>
</field>
</form>

Next, we need to look at the Ant tasks to generate these files. An annotated XML snippet is shown below.


<target name="xdoclet-web">
<taskdef classname="xdoclet.modules.web.WebDocletTask" classpathref="project.class.path" name="webdoclet"/>
<webdoclet destDir="etc/web" excludedTags="@author,@version,@todo" mergeDir="etc/merge">
<fileset dir="src">
<include name="**/*.java"/>
</fileset>

<!-- The strutsconfigxml element generates the struts-config.xml file. -->
<strutsconfigxml destDir="etc/web" mergeDir="etc/merge" version="1.1"/>

<!-- By including this element, the validation.xml file will be
generated based on your struts.validation tags. -->
<strutsdynaformvalidationxml/>

</webdoclet>
</target>

That’s all there is to creating and validating your DynaForm with XDoclet. A future revision to this tutorial will include a method to override the validation rules defined in an associated objects.

nick Articles

Struts Message Resources

July 29th, 2006

The MessageResources class allows a developer to easily support multiple languages, in addition to supporting multiple date and numeric formats. Another useful trait is that properly using resource bundles will allow the developer to store label strings in a centralized location, without having to duplicate the same string throughout your JSP code. For example, instead of having the string “First Name” in each form with a field for the user’s first name, you can simply refer to this property in the resources bundle with the following struts tag:

<bean:write key="label.first.name"/>

This will allow you to make changes easily, without having to open multiple JSPs or resorting to complicated regular expressions to change the label strings.

Usage

Getting started with message resource bundles requires you to:

  1. Create a message resources bundle for each locale you wish to support.
  2. Configure the web application to load the message resources bundle.
  3. Use the appropriate JSP tags to load the resources, or…
  4. …load the resource values from an Action class.

Creating the Resource Bundle

The default implementation of the MessageResources class takes a file with simple "key=value" lines as input. Below is our example message resources bundle file.

label.username=Username
label.password=Password
label.first.name=First Name
label.last.name=Last Name
label.email=Email Address
label.phone.number=Phone Number
label.welcome=Welcome back {0} {1}!

error.min.length=The input must be at least {0} characters in length.
error.max.length=The input cannot be longer than {0} characters in length.

The values with integers surrounded by brackets are a carry-over from the java.text.MessageFormat class. They allow the developer to pass in parameters that are inserted into the string. You can have up to four parameter fields per value string.

Configuration

There are two ways to tell Struts the location of your resource bundle: either by specifying it in your web.xml or in the struts-config.xml file. First, the web.xml configuration:

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
    org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>

    application
</param-name>
<param-value>
    com.systemmobile.example.ApplicationResources
</param-value>
</init-param>
</servlet>

This configuration states that the name of the resources bundle is ApplicationResources.properties and it is located in the com.systemmobile.example package. The ".properties" extension is implied; you do not have to include it in the configuration. If you also have various resource bundles based on locale, such as ApplicationResources_fr.properties to support French, you only need to specify the base file name, as listed above.

The second, and likely preferred, method of making your resource bundle available to your Struts application is to specify it in the struts-config.xml file:

<message-resources parameter="com.systemmobile.example.ApplicationResources"/>

The parameter attribute is required. The same notes apply for this configuration method as for the web.xml method regarding the location of the file in the package structure and multiple locales.

Using the struts-config.xml file to configure your message resources is preferred as it gives you quite a bit of additional flexibility:

  • You can list multiple message-resources tags to load messages from multiple files. If you do this, use the key attribute to give a unique name to each bundle. e.g.:
    <message-resources key="myResources" parameter="com.systemmobile.example.ApplicationResources"/>
    
    <message-resources key="moreResources" parameter="com.systemmobile.example.MoreApplicationResources"/>

    You would then have to give the key name when using the bean:message tag:

    <bean:message bundle="moreResources" key="some.message.key"/>
  • Setting the null attribute to "false" will display missing resource values as ???key??? instead of displaying null. This string is easily found during automated testing of your JSPs, making in-container unit testing more complete. (Details about how messages are retrieved from resource bundles can be found in the Internationalization section.)
    <message-resources parameter="com.systemmobile.example.ApplicationResources" null="false"/>
  • Additionally, the message-resources tag allows you to use your own implementation of the MessageResourcesFactory class, which is outside the scope of this article.

Where To Put The File

The most common cause of problems with the message resources on the struts-user mailing list is where to put the actual file in the WAR. The short answer is that the file/files must exist somewhere in your classpath. This can mean putting it into a JAR file, or putting it in the /WEB-INF/classes directory, or in a subdirectory under classes. The table below gives the location of the message bundle file, the assocated value of the "parameter" attribute for the message-resources tag, and a short description if necessary.

Resources Location parameter Value Description
/WEB-INF/classes/ApplicationResources.properties ApplicationResources The file is in the classes directory, which is in the web app’s classpath.
/WEB-INF/classes/resources/ApplicationResources.properties resources.ApplicationResources The file is in the "resources" directory, and therefore package, so the directory name is given. [1]
In the app.jar file, in the com.systemmobile.example package/directory. com.systemmobile.example.ApplicationResources The full path to the file in the JAR file.

Tags

The most common Struts tag to use is the bean:message tag. This tag allows you to load a specific message resource from the bundle using the "key" attribute. It also allows you to populate any or all of the four arguments in the value:

<bean:message key="label.password"/>
<bean:message key="error.min.length" arg0="6"/>

<bean:message key="label.welcome" arg0="Ralph" arg1="Nader"/>

The html:message tag allows you to display errors (default) or messages to the user, while html:errors will only display error messages. Messages and errors must be present in the request, obviously, or there will be nothing to display. Here is an example of displaying the messages:

<logic:messagesPresent message="true">
  <html:messages id="msg" message="true">

    <div class="success">
      <bean:write name="msg"/>
    </div><br/>
  </html:messages>
</logic:messagesPresent>

Other tags have limited support for message resources, such as html:link. The html:link tag allows you to specify the title text with the "titleKey" attribute. Many of the html tags support the "altKey" attribute to load the alternate text label value from the resources bundle.

Actions

You can also access message resources from within Action classes. The Action class has the following methods to obtain a reference to a MessageResource instance:


// returns a resource bundle for the locale specified in the request
protected MessageResources getResources(HttpServletRequest request);

// returns a resource bundle for the locale specified in the request,
// for the given key as given in the <message-resources/> element
protected MessageResources getResources(javax.servlet.http.HttpServletRequest request, java.lang.String key);

The MessageResources class will allow you to retrieve locale-dependent messages from the underlying resource bundle. The API for MessageResources can be found in Resources. Some of the more commonly used methods include:

// these methods load a resources key for the given locale
public String getMessage(java.util.Locale locale, java.lang.String key);
public String getMessage(java.util.Locale locale, java.lang.String key,
       java.lang.Object arg0);
public String getMessage(java.util.Locale locale, java.lang.String key,
       java.lang.Object[] args);
public String getMessage(java.util.Locale locale, java.lang.String key,
       java.lang.Object arg0, java.lang.Object arg1)
public String getMessage(java.util.Locale locale, java.lang.String key,
       java.lang.Object arg0, java.lang.Object arg1, java.lang.Object arg2);
public String getMessage(java.util.Locale locale, java.lang.String key, java.lang.Object arg0,
       java.lang.Object arg1, java.lang.Object arg2, java.lang.Object arg3);

// these methods load a resources key for the locale retrieved
// from the HttpServletRequest
public String getMessage(java.lang.String key);
public String getMessage(java.lang.String key, java.lang.Object arg0);
public String getMessage(java.lang.String key, java.lang.Object[] args);
public String getMessage(java.lang.String key, java.lang.Object arg0,
       java.lang.Object arg1);
public String getMessage(java.lang.String key, java.lang.Object arg0,
       java.lang.Object arg1, java.lang.Object arg2);
public String getMessage(java.lang.String key, java.lang.Object arg0,
       java.lang.Object arg1, java.lang.Object arg2, java.lang.Object arg3);

Returned Strings can be set as attributes in the request or session and passed back to the view layer. You’ll notice that some of the various overloaded getMessage(...) methods take Objects as arg0...arg3. This is the equivalent to the bean:message arg0...arg3 attributes.

In addition to the MessageResources class, a few other classes make use of resources bundles. ActionMessage is used to pass message resource keys from the action to the JSP. Messages can apply to specific bean properties or can be generic. The ActionError, subclass of ActionMessage, class uses the resource bundle keys to store error messages when form validation fails.

Internationalization

Loading a specific message resources bundle for a give locale is handled by the MessageResources class, or by it’s immediate subclass, PropertyMessageResources. Since you’re likely to use the PropertyMessageResources class, we’ll examine how it loads message resources for a key using the getMessage(Locale, String) method.

  1. The message is located using specific Locales. If the message cannot be found, more generic Locales are used. For instance if the message can’t be found in ApplicationResources_pt_br.properties (Brazilian Portuguese), the ApplicationResources_pt.properties file (and therefore Locale) will be searched. If the ApplicationResources_pt.properties file does not exist or the key is not found, the mesage will be retrieved from the ApplicationResources.properties file. Increasingly generic resource bundles are tried until the default Locale is used.
  2. If the message key is found, it is added to a Locale-specific cache and returned as a java.lang.String.
  3. If the message key is not found, null is returned if the returnNull attribute is true, which is the default. If returnNull is false, a string such as ???key??? is return, where key is the passed message resources key.

JSTL

The JSTL (JavaServer Pages Standard Tag Library) fmt tag has recently come into vogue as the preferred way to utilize the message resources functionality with JSPs. It also works quite well with Struts. Setting it up is pretty simple, as the rules about classpath and file location still apply. After downloading the JSTL jar and TLDs and copying them into the appropriate places in your application, put the following configuration block into your web.xml:

<context-param>
  <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
  <param-value>ApplicationResources</param-value>
</context-param>

The above configuration is if the file ApplicationResources.properties is located in the /WEB-INF/classes directory. See above for the guidelines about configuration.

Then put this taglib directive into your JSP:


<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>

Finally, the following tag will load a resource:

<fmt:message key="label.first.name"/>

Here are some additional examples of using the fmt tags to load resource values. (Note: these were taken from the Jakarta JSTL examples.)

// loading a resource from a specific bundle and populating a parameter
<fmt:message key="currentTime" bundle="${deBundle}">
 <fmt:param value="${currentDateString}"/>
</fmt:message>

// using the forEach iterator to populate paramters
<fmt:message key="serverInfo" bundle="${deBundle}">
 <c:forEach var="arg" items="${serverInfoArgs}">
  <fmt:param value="${arg}"/>

 </c:forEach>
</fmt:message>

Conclusion

The message resources functionality in Struts allows you to easily create fully internationalized web applications, as well as providing a convenient abstraction between messages and the JSPs. The resource values can be loaded from within actions or using the Struts tags, although the JSTL tags are rapidly gaining favor. I hope that this article clarified a few things for you regarding this handy and, sometimes confusing, feature of Struts.

About the Author

Nick Heudecker is a software developer with more than six years of experience designing and building enterprise applications. His firm, System Mobile, Inc., specializes in application integration, custom software development and wireless applications. He is a Sun Certified Java Programmer and is located in Chicago.

nick Articles