Adding Spice to Struts - Part 2
by: Samudra Gupta
Introduction
Last month, we explored one way of extending Struts DynaForm
capability to model the inheritance relationship through
configuration. This sort of extension is very useful and can
reduce the size of the configuration to a great degree and also
keeps the module more compact and flexible. This month, we shall
explore another way of extending the DynaForms in Struts to
model the inheritance relationship. Then, we will develop
another interesting aspect of Struts by using multiple resource
bundle files in a seamless manner.
DynaForm and Inheritance…
In part one we proposed a mechanism to
extend the DynaActionForm class and override the initialise()
method in order to combine the properties of both the parent
form bean and child form bean. That mechanism was simple enough
to understand but works to certain extents. This time we will
explore a mechanism, which is more complete in nature.
After implementing last month’s solution, Ashish and Myself were
very happy. Only a few days later, we faced some problems, when
we tried to access the included form bean properties from within
a JSP. The problem appeared that the Form tag from Struts tag
library could not find the getter() methods for the included
form bean properties. This was daunting, but as developers, we
should never give up. So we pushed ahead.
A new problem means a new solution. So we ventured to find
another way of modeling the inheritance mechanism using the
DynaForm configuration.
This time, we started looking at how Struts initializes the form
bean configurations. In this context, the starting point is the
Struts ActionServlet class. Interestingly enough, this
ActionServlet gave us a vital clue to what happens and what we
need to do to find a complete set and get access to our new form
bean configuration mechanism. Here is what we found out:
- The
entry point to the all Struts related configuration is the init() method
in the ActionServlet class.
- The
Struts framework supports module based configuration. That means we can
have multiple Struts configuration files for each module in a multi
modular application. This means that all the form bean configurations are
part of a ModuleConfig object.
- After
the initialization mechanism parses all the module configuration and the
initialization is over, the Struts calls the freeze() method on the
ModuleConfig object.
- This
means that once the control has returned from the initialization process
i.e the ActionServlet, it is not possible to modify the module
configuration. Thus, once a Form bean is configured, we will not be able
to set any new Form property to it.
- This
may come as confusing. Last month what we did is that we added more
key-values to the internal Map of the DynaFormBean. But adding more
key-values to the internal Map of the DynaForm bean does not tell the
Struts that each of those added properties do actually exist as
FormPropertyConfig object.
Unless,
each property of DynaForm is registered as a FormPropertyConfig object,
the Struts form tags will NOT be able to recognize those properties.
Considering these facts, we decided to extend the default Struts
Action Servlet class and provide our own implementation for the
form bean initialization. One other thing about Struts is that
it uses Commons Digester to parse the XML configuration files
and populate different configuration objects. As soon as we
decide to override the initialization method(s), we need to make
sure that we provide a mechanism to parse the Struts XML
configuration files. In Listing 1, we provide a pseudo
implementation of the overridden ActionServlet class and the
full source code is downloadable from here.
protected ModuleConfig initModuleConfig(String prefix, String paths)
throws ServletException
{
System.out.println("**Inside the initModule");
// Parse the configuration for this module
ModuleConfigFactory factoryObject =
ModuleConfigFactory.createFactory();
ModuleConfig config =
factoryObject.createModuleConfig(prefix);
// Support for module-wide ActionMapping type override
String mapping = getServletConfig().getInitParameter("mapping");
if (mapping != null)
{
config.setActionMappingClass(mapping);
}
// Configure the Digester instance we will use
Digester digester = initConfigDigester();
// Process each specified resource path
while (paths.length() > 0)
{
digester.push(config);
String path = null;
int comma = paths.indexOf(',');
if (comma >= 0)
{
path = paths.substring(0, comma).trim();
paths = paths.substring(comma + 1);
} else
{
path = paths.trim();
paths = "";
}
if (path.length() < 1)
{
break;
}
this.parseModuleConfigFile(prefix, paths, config, digester, path);
}
// Force creation and registration of DynaActionFormClass instances
// for all dynamic form beans we wil be using
FormBeanConfig fbs[] = config.findFormBeanConfigs();
System.out.println
("**The number of props for the prefix " + prefix + " is " + fbs.length);
for (int i = 0; i < fbs.length; i++)
{
System.out.println("**The dynamic attribute:
for form bean " + fbs[i].getName() + " is " + fbs[i].getDynamic());
if (fbs[i].getDynamic())
{
//check if this form bean config has includes property
FormPropertyConfig includes = fbs[i].findFormPropertyConfig("includes");
System.out.println
("**The includes prop found: " + includes + " for the form bean " + fbs[i].getName());
if (includes != null)
{
String formBeanToInclude = includes.getInitial();
//find the form bean configuration for the form bean to include
FormBeanConfig includeConfig =
config.findFormBeanConfig(formBeanToInclude);
//get all the properties of the form bean to include
FormPropertyConfig[] props = includeConfig.findFormPropertyConfigs();
for (int j = 0; j < props.length; j++)
{
FormPropertyConfig prop = props[j];
//now add this property as the part of original form bean
System.out.println("***Adding included prop : " + prop.getName());
fbs[i].addFormPropertyConfig(prop);
}
}
DynaActionFormClass.createDynaActionFormClass(fbs[i]);
}
}
return config;
}
Listing 1: Pseudo implementation of CustomActionServlet
There are two important points in this implementation.
- First
we initialise the Digester class and then pass on to it the config files
to pass and the appropriate configuration objects within Struts will be
configured according to the rules specified in conjunction with the
Digester instance.
- In
the next bit of code, we actually parse each form bean configuration,
identify if there is any "includes" property defined, load the
corresponding form bean properties and create FormPropertyConfig and then
create the DynaActionForm class with all the consolidated form bean
properties.
This way, we have a mechanism to model the inheritance
relationship with Dynamic Action Form configuration.
The next problem that we will consider is the problem with
consolidating different message resource files within Struts.
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|