Warning: mysql_real_escape_string(): No such file or directory in /home/dh_kxiiuj/codefez.com/wp-content/plugins/tla/textlinkads.php on line 641

Source Code | CodeFez

This article is the fourth in a series of articles on the build tool called NAnt. It describes how to use C# to create custom NAnt tasks. The information provided here builds on the previous articles, which can be found here, here and here. In particular, see the last two articles. The source code for this article, and for the last two articles, is available here.

The techniques provided for extending NAnt represent an excellent example of modern code design. The whole concept of plug and play, extensible, architectures is very much at the apex of current application design theory, and the folks who brought us NAnt demonstrate exactly how this kind of architecture should behave. As you will see while reading this article, the concepts involved are easy to understand, and easy to use. This is an excellent example of the kind of intuitive, cutting edge program design that lies behind the best modern software.

Since this article focuses on building custom NAnt tasks, it seems appropriate to spend a few sentences defining our terms. NAnt is based on XML scripts. Each script contains XML code built around a series of tasks. A task plays a similar role in NAnt to a method or class in C#. It is a chunk of executable code.

Most people who use NAnt rely on the built in tasks that come with NAnt. For instance, the echo task writes a string to the console.

<project name="EchoProject" default="talk">

<target name="talk">
<echo message="This is a simple echo task."/>
</target>

</project>

If you save this file as echo.build, and then run it with this command nant -buildfile:echo.build, the output would look like this:

[D:\temp\bar]nant -buildfile:echo.build
NAnt 0.85 (Build 0.85.1932.0; rc3; 4/16/2005)
http://nant.sourceforge.net

Buildfile: file:///D:/temp/bar/echo.build
Target framework: Microsoft .NET Framework 1.1
Target(s) specified: talk

talk:

[echo] This is a simple echo task.

BUILD SUCCEEDED

Total time: 0 seconds. 

Note the highlighted line near the bottom of this listing where our text is echoed to the console. Besides the echo task, there are many other built in tasks, such as the csc task, used to build CSharp projects, or the exec task, used to run a system command.

#### Putting the Config Script in a Task

In the previous article in this series, you saw how to write C# script that can be embedded directly in a NAnt build file. In that article, the goal was to make identical changes to a series of .NET app.config or web.config files. This article will take that C# script from the previous article, embed it in a task called ConfigTask. In particular, the ConfigTask will be stored in a .NET assembly. Once you have built the assembly, you will be able to reuse it in multiple projects.

The relevant code from the last article is shown in Listings 0, 1 and 2. In particular, the code highlighted in dark blue in Listing 1 is the part we need to move into our .NET assembly. Listing two shows a second build file that this file relies upon. These files also assume that there are three files called app.config in subdirectories of the current directory. These config files are the files that are to be updated by this code. For clarification, please read the previous articles and download the source code.

Listing 0: The app.config file which is modified by the code shown in Listings 1 and 2.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
</appSettings>
</configuration>

Listing 1: Here is the build file, called default.build, from the previous article. It contains, highlighted in blue, the code that we want to reuse.

<project name="ConfigChanger" default="fancyCode">

<target name="talk">
<echo message="You ran default.build"/>
</target>

<target name="setValues">
<property name="fileName" value="config01\app.config"/>
<property name="attributeName" value="DatabaseName"/>
<property name="valueName" value="Zen"/>
</target>

<target name="configWrite" depends="talk">

<nant buildfile="nant.build" target="configWrite">
<properties>
<property name="fileName" value="${fileName}"/> <property name="attributeName" value="${attributeName}"/>
<property name="valueName" value="${valueName}"/> </properties> </nant> </target> <target name="fancyCode"> <script language="C#"> <code> <![CDATA[ public static void NewProp( Project project, string fileName, string attributeName, string valueName) { string fileNameProperty = "fileName"; string attributeNameProperty = "attributeName"; string valueNameProperty = "valueName"; project.Properties.Remove(fileNameProperty); project.Properties.Add(fileNameProperty, fileName); project.Properties.Remove(attributeNameProperty); project.Properties.Add(attributeNameProperty, attributeName); project.Properties.Remove(valueNameProperty); project.Properties.Add(valueNameProperty, valueName); } public static void DoFileNames(Project project, string attributeName, string valueName) { String[] fileNames = {"config01\\App.config", "config02\\App.config", "config03\\App.config"}; for (int i = 0; i < 3; i++) { NewProp(project, fileNames[i], attributeName, valueName); project.Execute("configWrite"); } } public static void ScriptMain(Project project) { project.Execute("setValues"); DoFileNames(project, "DatabaseName", "Zen"); DoFileNames(project, "AppName", "TradeMaster"); DoFileNames(project, "FtpAddress", "localhost"); } ]]> </code> </script> </target> </project> Listing 2: This file, called nant.build, is a dependency of the default.build file shown in Listing 1. <project name="testName" default="talk"> <target name="talk"> <echo message="You ran NAnt.build"/> </target> <target name="configWrite" depends="talk"> <xmlpoke file="${fileName}"
xpath="/configuration/appSettings/add[@key='${attributeName}']/@value" value='${valueName}'>
</xmlpoke>

</target>

</project>

Since these three files were exhaustively discussed in the previous article, I will say no more about them here. Instead, I will show you, in Listing 3, the complete code for the .NET assembly that we are going to create.

Listing 3: Here is the first version of the code for the .NET assembly which will contain our new task. You should save this code to disk as ConfigTask.cs.

using System;
using NAnt.Core;
using NAnt.Core.Attributes;

{
{
public void NewProp(Project project,
string fileName,
string attributeName,
string valueName)
{
const string fileNameProperty = "fileName";
const string attributeNameProperty = "attributeName";
const string valueNameProperty = "valueName";

project.Properties.Remove(fileNameProperty);

project.Properties.Remove(attributeNameProperty);

project.Properties.Remove(valueNameProperty);
}

public void DoFileNames(Project project, string attributeName, string valueName)
{
String[] fileNames = {"config01\\App.config",
"config02\\App.config",
"config03\\App.config"};

for (int i = 0; i < 3; i++)
{
NewProp(project, fileNames[i], attributeName, valueName);
project.Execute("configWrite");
}

}

public void RunConfig(Project project)
{
project.Execute("setValues");
DoFileNames(project, "DatabaseName", "Zendo");
}

{
RunConfig(Project);
}
}
}

Here, with all extraneous code removed, is the core structure around which this code is build:

using System;
using NAnt.Core;
using NAnt.Core.Attributes;

{
{
{
RunConfig(Project);
}
}
}

As you can see, we use the TaskName attribute at the top of our class, and descend the class itself from the NAnt class called Task. We then have to override a single method called ExecuteTask. From inside that method, we call our custom method named RunConfig. In the previous article in this series, the RunConfig method was called ScriptMain. This new version of our code is identical to what you saw in the previous article, except for this one name change, and the deletion of the static declarations for each of the methods.

#### Building and Calling the Task

The build file which will compile our assembly , load it into memory, and execute our task is shown in Listing 4.

Listing 4: The file config.build compiles our assembly, loads it into memory, and executes our task. Type nant -buildfile:config.build to run this file.

<?xml version="1.0"?>
<project name="NAnt" default="run">

<target name="talk">
<echo message="You ran default.build"/>
</target>

<target name="setValues">
<property name="fileName" value="config01\app.config"/>
<property name="attributeName" value="DatabaseName"/>
<property name="valueName" value="Zen"/>
</target>

<target name="configWrite" depends="talk">

<nant buildfile="nant.build" target="configWrite">
<properties>
<property name="fileName" value="${fileName}"/> <property name="attributeName" value="${attributeName}"/>
<property name="valueName" value="${valueName}"/> </properties> </nant> </target> <!-- Compile the test task and add it then use it. --> <target name="build"> <mkdir dir="bin" /> <csc target="library" output="${libName}">
<sources>
</sources>
<references basedir="${nant::get-base-directory()}"> <include name="NAnt.Core.dll"/> </references> </csc> </target> <target name="run" depends="build"> <!-- Dynamically load the tasks in the Task assembly. --> <loadtasks assembly="${libName}" />

<!-- Call our new task -->
</target>

<target name="clean">
<!-- Delete the build output. -->
<property name="configFull" value="${directory::get-current-directory()}\${libName}"/>
<echo message="Deleting ${configFull}"/> <delete file="${configFull}" if="${file::exists('bin\ConfigTask.dll')}" /> </target> </project> The build target found in this code is straightforward NAnt code for creating an assembly.  <property name="libName" value = "bin\ConfigTask.dll"/> <!-- Compile the test task and add it then use it. --> <target name="build"> <mkdir dir="bin" /> <csc target="library" output="${libName}">
<sources>
</sources>
<references basedir="${nant::get-base-directory()}"> <include name="NAnt.Core.dll"/> </references> </csc> </target> The built in csc task is used to perform the compilation, and the library is saved to the relative path bin\ConfigTask. If the bin directory does not exist, it will be created automatically using the built in mkdir task. Note that the code references NAnt.Core.dll. This library contains the Task class referenced by our C# code. Any developer who wants to create a large number of sophisticated tasks should become familiar with this DLL. Once the library is built, it needs to be loaded into memory. The following code performs that task: <property name="libName" value = "bin\ConfigTask.dll"/> <target name="run" depends="build"> <!-- Dynamically load the tasks in the Task assembly. --> <loadtasks assembly="${libName}" />

<!-- Call our new task, converts the message attribute to all caps and displays it. -->
</target>

 <configtask/>

Assuming that nant.build is in place, and you have three app.config files like the one shown in Listing 0 are in the appropriate place, then you should find changes made to the config files after running the task.

#### Passing Information into Our Task

As it exists now, our task has a considerable amount of hard coded information in it. For instance, the names of the attributes in the config files that we want to change are hard coded, as well as the names of the config files themselves. There are several ways to remedy this situation, but perhaps the simplest would be to pass in a file name, and then have the C# code in our task read data from that file.The file, would, of course, contain data such as the paths to our config files, as well as the attribute and value pairs that we want to modify.

The code shown in Listing 5 extends our assembly to include an attribute for our task called fileName. You can use this attribute to pass in the file name which will contain configurable data such as the names of the config files and the attributes inside them that you want to change. The code shown here demonstrates how to pass the file name into the task, but the rest of the work will be left either to a future article, or as an exercise for the reader.

Listing 5: Code for passing in data to our assembly. In particular, a new attribute called fileName has been added to this code.

using System;
using NAnt.Core;
using NAnt.Core.Attributes;

{
{
private string _fileName;

public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}

public static void NewProp(Project project,
string fileName,
string attributeName,
string valueName)
{
const string fileNameProperty = "fileName";
const string attributeNameProperty = "attributeName";
const string valueNameProperty = "valueName";

project.Properties.Remove(fileNameProperty);

project.Properties.Remove(attributeNameProperty);

project.Properties.Remove(valueNameProperty);
}

public static void DoFileNames(Project project, string attributeName, string valueName)
{
String[] fileNames = {"config01\\App.config",
"config02\\App.config",
"config03\\App.config"};

for (int i = 0; i < 3; i++)
{
NewProp(project, fileNames[i], attributeName, valueName);
project.Execute("configWrite");
}

}

public static void RunConfig(Project project)
{
project.Execute("setValues");
DoFileNames(project, "DatabaseName", "Zendo");
}

{
RunConfig(Project);
Log(Level.Info, "You passed in: " + _fileName);
}

}
}

The code that we care about in this new version of our assembly is really very simple:

private string _fileName;

public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}

A private variable named _fileName is declared at the top of the file. Then the attribute for our task is declared, and finally we create a simple property called FileName which implements the new attribute. Please note that we have set the Required flag to true, which means that the fileName attribute must be included when you call this task.

Making use of this attribute is very simple. As you recall, in Listing 4 we called our task from a build file with this code:

<configtask/>

<configtask fileName="MyFile.txt"/>

At the very end of our new version of the assembly, shown in Listing 5, we print out the value of our attribute using the Log method of Task::Project. In actual working code, the task should open the file and read data from it. But for now, we will just print out the file name:

protected override void ExecuteTask()
{
RunConfig(Project);
Log(Level.Info, "You passed in: " + _fileName);
}

#### Summary

This short article has provided the basic information you need to create your own NAnt tasks. You have seen that tasks are stored into assemblies, and you have seen the code to create a simple assembly that contains a task. A build file was shown that can build the assembly, load it into memory, and then call it. The article ended with a description of how to pass information into a task.

If understand the code demonstrated in this and previous articles, then you should be master of enough information to really put NAnt to work. The NAnt project is beautiful designed, and the mechanisms it provides for either writing C# script or creating your own tasks are both elegant and highly usable.

Five or six years ago, I remember sitting in the LA airport talking to my friend Mark Miller. At the time, he was interested in creating a plug and play, extensible architecture for his CodeRush product. He was very fired up about the concept, and we talked about the idea for over an hour. All these years later, projects like Eclipse and NAnt have brought that vision to fruition. A lot of smart programmers have been thinking about these ideas for years, and it is great to see them as beautifully executed as they are in the NAnt project.

# Using NAnt to Update .NET Config Files, Part 02

This article completes the two part series on using NAnt to alter .NET config files. The previous article in this series demonstrated how to use NAnt properties, how to use multiple NAnt build files in a single project, and how to use xmlpeek and xmlpoke. This article will show how to pass data back and forth between NAnt files, how to reuse NAnt code, and how to add some simple C# scripts into your build files. This later technique will allow you to add the expressive power of C# to a simple NAnt XML build script.

#### Code Reuse in NAnt

Let’s take a second look at the NAnt code for updating a .NET config file:

	<target name="configWrite">
<xmlpoke
file="Config01/app.config"
</xmlpoke>
</target>

Notice the two areas shown in bold. The first is the name of an attribute in the config file that is marked for alteration. The second is the new value to be assigned to the attribute.

Now take a second look at the .NET config file we want to change:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
</appSettings>
</configuration>

It should be clear that the areas of the NAnt code shown in bold reference the areas in the config file shown in bold. Therefore, if we want to write code to change the DatabaseName in the config file, we would come up with something like this:

	<target name="configWrite">
<xmlpoke
file="Config01/app.config"
value="Zen">
</xmlpoke>
</target>

After running both code fragments shown so far in this section, the config file would look like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
</appSettings>
</configuration>

If you compare the two NAnt code samples you can see that they are identical except for two words. If we were writing C# code, we would see immediately that there is no need to write out two nearly identical blocks of code. Instead, we would create a single block of code, put it in a method, and pass in the two variable parts as parameters. Our C# code would then support a simple form of code reuse: the same method would be called twice; it would be reused. As you shall see, the same thing can be accomplished in NAnt code through the use of properties.

Consider the block of NAnt code shown in Listing 0, which takes us part way to our goal:

Listing 0: This chunk of code abstracts parts of the xmlpoke task into two properties called attributeName and valueName. Though not true variables, these properties can, at least potentially, be changed dynamically.

<project name="ConfigChanger" default="configWrite">

<property name="attributeName" value="DatabaseName"/>
<property name="valueName" value="Zen"/>

<target name="configWrite">
<xmlpoke
file="Config01/app.config"
xpath="/configuration/appSettings/add[@key='${attributeName}']/@value" value='${valueName}'>
</xmlpoke>
</target>

</project>

Two properties are defined at the top of the file. Each of these properties are then used in the target called configWrite. The end result is that the configWrite target now has two "variables" in it, that can be changed depending on the value of our two properties. The problem we need to solve now is finding a way to dynamically change these properties.

#### Passing Data Between Two NAnt Files

We are now part way to our solution. What we need is a way to set the two properties shown in Listing 0 called attributeName and valueName from outside of this file. In particular, we want to be able to call the code shown in Listing 0 from our default.build file. To call one build file from another build file you should use a built in task called nant. When I say that nant is a built in task, I mean that it is part of NAnt itself, and can be called by anyone who uses the product.

Consider the following two files, the first called nant.build and the second default.build:

Listing 1: nant.build is the file that will be called. It is the callee.

<project name="testName" default="talk">

<target name="talk">
<echo message="You ran nant.build"/>
</target>

<target name="configWrite" depends="talk">

<xmlpoke
file="Config01/app.config"
xpath="/configuration/appSettings/add[@key='${attributeName}']/@value" value='${valueName}'>
</xmlpoke>
</target>

</project>

Listing 2: default.build is the main file. It is the one that calls into nant.build. It is the caller.

<project name="ConfigChanger" default="configWrite">

<target name="talk">
<echo message="You ran default.build"/>
</target>

<target name="configWrite" depends="talk">

<nant buildfile="nant.build" target="configWrite">
<properties>
<property name="attributeName" value="DatabaseName"/>
<property name="valueName" value="Velocity"/>
</properties>
</nant>

</target>

</project>

Take a look at nant.build, shown in Listing 1. As you can see, it uses the properties called attributeName and valueName, but they are not defined anywhere inside the file. Looking at Listing 2, however, we see that there is a section of the target called configWrite that defines both of these properties:

<properties>
<property name="attributeName" value="DatabaseName"/>
<property name="valueName" value="Velocity"/>
</properties>

If you look closer, you can see that the nested element called properties is part of a larger task called nant. The built-in task called nant is used to call our second build file. The nant task explicitly supports a nested element called properties, which is designed to allow you to pass properties back and forth between NAnt build files.

	<nant buildfile="nant.build" target="configWrite">

For good measure, I specify the desired target in nant.build. This step is not entirely necessary since configWrite is the default target in nant.build. However, I wanted to show you how the syntax for calling a particular target works in case you ever need it. Here’s another way of looking at the syntax for the nant task:

	<target name="configWrite" depends="talk">

<nant buildfile="nant.build" target="configWrite">
.... Code omitted here.
</nant>

</target>

The code that is omitted defines the properties that will be passed to the second build file.

Take one more moment to look again at the code discussed in this section of the text:

<nant buildfile="nant.build" target="configWrite">
<properties>
<property name="attributeName" value="DatabaseName"/>
<property name="valueName" value="Velocity"/>
</properties>
</nant>

First we call the nant task, then we specify the properties that will be set in the targeted build file. Once you understand how to pass properties back and forth between NAnt build files, you will have mastered a key building block that allows you to tap into the power and flexibility of this tool.

#### Changing Multiple Config Files at Once

You now have enough information to come up with your own solutions to our problem. However, I want to show how to solve this problem by introducing C# script into our NAnt build files. Once you know how to add a little script of this type to your files, you will find that there is very little you cannot accomplish when writing NAnt build scripts.

Recall that we want to change three config files at one time. In the previous version of nant.build that I have shown you, the name of the config file was hard coded. To give us more flexibility, I’m going to slightly alter nant.build. In Listing 3, the fileName is specified as a property, and hence can be changed at run time.

Listing 3: A new version of NAnt.build, that will be called by default.build.

<project name="testName" default="talk">

<target name="talk">
<echo message="You ran NAnt.build"/>
</target>

<target name="configWrite" depends="talk">

<xmlpoke
file="${fileName}" xpath="/configuration/appSettings/add[@key='${attributeName}']/@value"
value='${valueName}'> </xmlpoke> </target> </project> This code supports changing the file name of the config file, the name of the attribute, and the value of that attribute. This one short build file can thus be used to change multiple properties in multiple config files. All we have to do is find a way to call this file with the appropriate properties set to the appropriate values. Listing 4 shows you way to solve this problem. Listing 4: Here is a new version of default.build. By changing three words in this script, you can change the values of attributes in multiple config files. <project name="ConfigChanger" default="fancyCode"> <target name="talk"> <echo message="You ran default.build"/> </target> <target name="setValues"> <property name="fileName" value="config01\app.config"/> <property name="attributeName" value="DatabaseName"/> <property name="valueName" value="Zen"/> </target> <target name="configWrite" depends="talk"> <nant buildfile="nant.build" target="configWrite"> <properties> <property name="fileName" value="${fileName}"/>
<property name="attributeName" value="${attributeName}"/> <property name="valueName" value="${valueName}"/>
</properties>
</nant>

</target>

<target name="fancyCode">

<script language="C#">
<code>
<![CDATA[
public static void NewProp(
Project project, string fileName,
string attributeName, string valueName)
{
string fileNameProperty = "fileName";
string attributeNameProperty = "attributeName";
string valueNameProperty = "valueName";

project.Properties.Remove(fileNameProperty);

project.Properties.Remove(attributeNameProperty);

project.Properties.Remove(valueNameProperty);
}

public static void DoFileNames(Project project,
string attributeName, string valueName)
{
String[] fileNames = {"config01\\App.config",
"config02\\App.config",
"config03\\App.config"};

for (int i = 0; i < 3; i++)
{
NewProp(project, fileNames[i],
attributeName, valueName);
project.Execute("configWrite");
}

}

public static void ScriptMain(Project project)
{
project.Execute("setValues");
DoFileNames(project, "DatabaseName", "Zen");
}
]]>
</code>
</script>

</target>

</project>

If you look at this code, you will see that it includes not only XML, but also C# code. NAnt gives you the ability to embed C# script in the midst of your XML build scripts. I will explain a little bit about writing C# script in a build file in one moment. Before doing that, however, I want to spend a moment discussing how to use the build file shown in Listing 4.

To run the build file itself, you need only type nant at the command line. Assuming that nant.exe is on your path, then this script will be executed, and the target called fancyCode will run by default.

If you want to change the values of attributes in your config files, you need focus on only one C# method from Listing 4. The method in question is called ScriptMain:

	public static void ScriptMain(Project project)
{
project.Execute("setValues");
DoFileNames(project, "DatabaseName", "Zen");
}

As shown, this method sets the values in three separate .NET App.config or Web.config files. In particular, it sets the DatabaseName to Zen, the AppName to TradeMaster and the FtpAddress to localhost. If you would rather set them to Velocity, TradeMonster, and ftp.elvenware.com, then you would alter the code so that it reads as follows:

	public static void ScriptMain(Project project)
{
project.Execute("setValues");
DoFileNames(project, "DatabaseName", "Velocity");
}

As you can see, we only had to change three simple string literals, and then rerun the script. The result was that all three config files were updated. The first time we ran the script the config files looked like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
</appSettings>
</configuration>

After changing our three constants and re-running the script, the files looked like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
</appSettings>
</configuration> 

#### Understanding C# Script Use in NAnt

Let’s take a moment to try to understand how C# scripting in a NAnt file works. Consider the following very simple script.

Listing 5: A very simple NAnt build file that contains a simple script section.

<project name="SeeProperties" default="yourTest">

<target name="yourTest">

<script language="C#">
<code>
<![CDATA[
public static void ScriptMain(Project project)
{
project.Log(Level.Info, "What we think, we become");
}
]]>
</code>
</script>

</target>

</project>

The default target for this simple build file contains C# script. There is one C# method called ScriptMain. It takes a parameter of type Project. If you want to create a method in a target that will be called by default, then you should define it as shown here. That is, it should have the name ScriptMain and it should take a parameter of type Project. It will then be called by default.

NOTE: There is also a way to call a method explicitly from your code that is not called ScriptMain and does not take Project as a parameter. For an example, see the section called Other Options, found at the end of this file.In the code we are creating, however, we will need an instance of class Project, so ScriptMain suits our purposes.

In the simple example shown in Listing 5, we call a method of the built in Project class called Log. It writes information to the screen, much like the C# method called Console.Write.

We need to use not the Log method, but a property of the Project class called Properties. It gives us access to all the properties in our project, including the properties called attributeName, valueName, and fileName. But before we do that, let’s see how to use Project.Properties.

#### Using Project.Properties

Project.Properties is of type PropertyDictionary. As you can see from studying the following code, the NAnt class called PropertyDictionary supports the C# IEnumerator interface. Using this interface, we can enumerate over all the members of the Properties class. This enumeration lets us see the dozens of properties found in even the smallest NAnt project. I can’t show you all of them in this article, but here is a simple build script that will allow you to view the properties of a NAnt project on your own machine:

<target name="yourTest">

<script language="C#">
<code>
<![CDATA[
public static void ScriptMain(Project project)
{
IEnumerator enums = project.Properties.GetEnumerator();
while(enums.MoveNext())
{
DictionaryEntry entry = (DictionaryEntry)enums.Current;
project.Log(Level.Info, entry.Key.ToString());
project.Log(Level.Info, entry.Value.ToString());
}
project.Execute("talk");
}
]]>
</code>
</script>

</target>

This code first accesses the IEnumerator interface of Project.Properties. It then uses the MoveNext method of the interface to iterate over all the properties in the project. As each property is discovered, the code prints out its name and the value assigned to it.

#### Calling Project.Properties to Access our Config Files

By now you should have enough theory under your belt to understand the code you saw in Listing 4. Notice that our ScriptMain method begins by calling Project.Execute:

public static void ScriptMain(Project project)
{
project.Execute("setValues");
DoFileNames(project, "DatabaseName", "Zen");
}

As you can probably guess, calling project.Execute allows us to execute a particular target in our build file. In this case, we want to call setValues so that we can be sure that instances of the properties called fileName, attributeName and valueName exist:

<target name="setValues">
<property name="fileName" value="config01\app.config"/>
<property name="attributeName" value="DatabaseName"/>
<property name="valueName" value="Zen"/>
</target>  

It is not important what values are in these properties, we only want to ensure that the properties exist. Exactly why this properties must exist will become clear in just one moment.

The next step is to call a method we defined called DoFileNames:

public static void DoFileNames(Project project, string attributeName, string valueName)
{
String[] fileNames = {"config01\\App.config",
"config02\\App.config",
"config03\\App.config"};

for (int i = 0; i < 3; i++)
{
NewProp(project, fileNames[i], attributeName, valueName);
project.Execute("configWrite");
}
}

This method first defines an array of fileNames. Here we can list all the .NET app.config or web.config files that we want to alter. The code then enters a loop which calls a method we defined named NewProp. The code then execute the target called configWrite. The loop calls NewProp three times, one for each of the config files that we want to alter.

NewProp begins by declaring string constants that define the attribute values in the config files that we want to change. We then need to set these attributes to the appropriate value. One simple way to do this is to delete any existing property of that name, and then add the property in again with a new value:

public static void NewProp(Project project,
string fileName,
string attributeName,
string valueName)
{
const string fileNameProperty = "fileName";
const string attributeNameProperty = "attributeName";
const string valueNameProperty = "valueName";

project.Properties.Remove(fileNameProperty);

project.Properties.Remove(attributeNameProperty);

project.Properties.Remove(valueNameProperty);
}

The first time we call this method, we are in danger of trying to remove a property that does not exist. That is why I called the setValues target before calling this method. setValues ensures that the value we want to delete really exists.Then it is safe to call Remove::

 project.Properties.Remove(fileNameProperty);

We are then free to add the property in again, this time associating it with a new value:

 project.Properties.Add(fileNameProperty, fileName);

Once we have added in all the properties set to the values we want, then the DoFileNames method calls configWrite.

 project.Execute("configWrite")

As you recall configWrite is a target in the default.build file:

<target name="configWrite" depends="talk">

<nant buildfile="nant.build" target="configWrite">
<properties>
<property name="fileName" value="${fileName}"/> <property name="attributeName" value="${attributeName}"/>
<property name="valueName" value="${valueName}"/> </properties> </nant> </target> By the time configWrite is called, each of the three properties, fileName, attributeName, and valueName, are set to the appropriate values. Now we can call nant.build and update the attributes found in the config files. Everything should make sense to you by now. But just in case, let’s go back now to the beginning and take a second look at ScriptMain. public static void ScriptMain(Project project) { project.Execute("setValues"); DoFileNames(project, "DatabaseName", "Zen"); DoFileNames(project, "AppName", "TradeMaster"); DoFileNames(project, "FtpAddress", "localhost"); } Here you can see that we call DoFileNames three times. Each time we pass in a pair of attributeNames and valueNames. Each pair sets a different attribute in all three config files. If we wanted to add more configurable attributes to our files, we would just call DoFileNames once more for each new configurable attribute. #### Other Options You have now seen all the important code that I wanted to show you in this article. In this section I will simple tack on a few more tips that you might find useful if you want to write code like that shown in this article. You have seen you how to write C# code with an entry point called ScriptMain. Here is how to write code that includes a method with an arbitrary name that can be called from an arbitrary point in a task: <project name="SimpleFunction" default="main"> <target name="main"> <script language="C#" prefix="MyMethods" > <code> <![CDATA[ [Function("SimpleFunction")] public static string SimpleFunction() { String buddhaSaying = "Holding on to anger is like " + "grasping a hot coal with the intent of throwing "+ "it at someone else; you are the one getting burned."; return buddhaSaying; } ]]> </code> </script> <echo message='${MyMethods::SimpleFunction()}'/>

</target>

</project>

Save this file as simpleFunction.build and call it by writing the following at the command prompt:

nant -buildfile:simpleFunction.build

Note the echo task near the end of this listing. It calls the method we have created called SimpleFunction. The function returns a String, which is in turn displayed by the echo task.

By creating your own functions, or by working with a NAnt feature called an Expression, you can do many amazing things with NAnt build files. For instance, I could have gotten the values for the properties in the config file from the DOS environment. I did this in an earlier version of the script shown in this article. Here is an example of how that code works.

	<target name="configWrite" depends="talk">

<nant buildfile="nant.build" target="configWrite">
<properties>
<property name="fileName"
value="${environment::get-variable('fileName')}"/> <property name="attributeName" value="${environment::get-variable('attributeName')}"/>
<property name="valueName"
value="${environment::get-variable('valueName')}"/> </properties> </nant> </target> Sometimes you might need a little more room. In a case like that, you can create your own task using C# script: <target name="myTask"> <script language="C#" prefix="test" > <code> <![CDATA[ [TaskName("usertask")] public class TestTask : Task { #region Private Instance Fields private string _fileName; #endregion Private Instance Fields #region Public Instance Properties [TaskAttribute("FileName", Required=true)] public string FileName { get { return _fileName; } set { _fileName = value; } } #endregion Public Instance Properties #region Override implementation of Task protected override void ExecuteTask() { Project.Execute("talk"); Log(Level.Info, _fileName.ToUpper()); } #endregion Override implementation of Task } ]]> </code> </script> <usertask FileName='app.config'/> </target> You can also write a C# assembly that defines a new task. However, I will leave that subject for another article. For now, you can find out more about writing Scripts here. #### Summary In this article, you have learned how to use some of the more advanced NAnt features. In particular, you have learned about: 1. Passing data back and forth between NAnt files by using properties 2. Writing C# script to add more flexibility to your build files. Future article on this subject may tackle the job of creating new NAnt tasks in separate C# assemblies that can be easily shared with other developers. Such an undertaking is in many ways similar to the C# scripting tasks shown here, only your C# code goes into a standard .NET assembly, and not into a NAnt build file. # Using NAnt to Update .NET Config Files, Part 01 This is the first of a two part article on updating Microsoft app.config or web.config files with the open source tool called NAnt. This is a relatively advanced article designed to teach you some of the powerful features found in the NAnt build tool. A previous article presented the reader with a basic introduction to the free build tool called NAnt. This article will focus on a technique for updating multiple .NET config files at one time. Technology covered includes: • Using multiple NAnt build files and calling one build file from another • Using xmlpoke and xmlpeek • Working with xpath statements. This is the most technical part of the article, and requires at least a passing understanding of XML syntax. Hopefully, the technique shown for working with config files will prove to be useful in and of itself, but the main focus of this article will be the discussions of NAnt technologies such as xmlpoke and multiple build files. I should point out that there are other articles on the web about using NAnt to change .NET config files. Indeed it is a natural task to perform with a tool like NAnt. However, the techniques shown here I developed myself. Indeed none of the articles that I found on this subject did more than discuss the theory behind this idea, that is, none of them showed a specific implementation of how to do it. #### Defining the Problem Space For the programming project I am currently working on, I have a single Visual Studio solution that contains about 12 different assemblies and programs. Almost all of the programs, and several of the unit test assemblies, have their own config files. As a rule, I want each project to share a large number, if not all, of the settings accessed by the other projects. In other words, I want to find a way to make identical minor changes to each of my multiple config files. One way to solve this kind of problem is to have multiple custom configuration files. One of the files, for instance, could contain only FTP settings. I could then have each of the programs access this single configuration file to get the FTP setttings, and access another single file to get the database settings. The team decided that was an awkward solution, so we switched to having one large config file for each project. Given this new system, I now need to simultaneously update any one of various different sections of my numerous config files. For instance, I might want to change the database server listed in each config file to server A, and the FTP server to server B. Then later, I might want to set both the database server and the FTP server to machine B, and later, I might want the FTP server to be A and database server to be B. In practice, there are other sections of the config files that need to be changed independently of the other settings. The end result is a rather confusing set of changes that need to occur simultaneously to some four to six different config files. There are probably a hundred different ways to use NAnt to change config files in the manner outlined in the last two paragraphs. In this article I will outline one particular solution. #### Default NAnt Files The solution I will propose involves creating two NAnt build files that reside in the same directory. These files will work in tandem to access multiple config files. All NAnt build files end with the extension .build. For instance, a typical name for a NAnt file would be NAnt.build. To run NAnt, you simple need to have NAnt.exe on your path. You then type nant at the command prompt, and NAnt will seek out the build file in the current directory and run it. So what happens if there are multiple build files in the same directory? Does NAnt run them all? Does it select one at random? It turns out that simply running NAnt with no parameters in a directory where there are multiple build files can be an error. For instance, consider this directory containing two build files: [D:\temp\bar]dir Volume in drive D is ChasDiskD Serial number is 4D89:2760 Directory of D:\temp\bar\* 9/20/2005 13:17 <DIR> . 9/20/2005 13:17 <DIR> .. 9/20/2005 12:13 120 foo.build 9/20/2005 12:13 120 nant.build 240 bytes in 2 files and 2 dirs 8,192 bytes allocated 15,964,147,712 bytes free If you type nant in this directory, you get an error: [D:\temp\bar]nant NAnt 0.85 (Build 0.85.1932.0; rc3; 4/16/2005) Copyright (C) 2001-2005 Gerry Shaw http://nant.sourceforge.net BUILD FAILED More than one '*.build' file found in 'D:\temp\bar' and no default.build exists. Use -buildfile: to specify the build file to execute or create a default.build file. For more information regarding the cause of the build failure, run the build again in debug mode. Try 'nant -help' for more information [D:\temp\bar] If you read the error message shown here, you can see what needs to be done. One solution is to create a build file called default.build, or else rename one of the existing build files to default.build. Let’s assume that we have created a new build file called default.build: [D:\temp\bar]dir Volume in drive D is ChasDiskD Serial number is 4D89:2760 Directory of D:\temp\bar\* 9/20/2005 13:26 <DIR> . 9/20/2005 13:26 <DIR> .. 9/20/2005 13:27 136 default.build 9/20/2005 13:27 132 foo.build 9/20/2005 13:27 133 nant.build 401 bytes in 3 files and 2 dirs 12,288 bytes allocated 15,964,082,176 bytes free Assume that each of the files has single task designed to print out the name of the build file. For instance, default.build looks like this: <project name="testName" default="talk"> <target name="talk"> <echo message="You ran default.build"/> </target> </project> Likewise, the file called NAnt.build looks like this: <project name="testName" default="talk"> <target name="talk"> <echo message="You ran NAnt.build"/> </target> </project> Both of these files represent a sort of "hello world" for NAnt. When you run them, they print out a simple string defined in an echo task. When you type NAnt in the current directory, this is the result: [D:\temp\bar]nant NAnt 0.85 (Build 0.85.1932.0; rc3; 4/16/2005) Copyright (C) 2001-2005 Gerry Shaw http://nant.sourceforge.net Buildfile: file:///D:/temp/bar/default.build Target framework: Microsoft .NET Framework 1.1 Target(s) specified: talk talk: [echo] You ran default.build BUILD SUCCEEDED Total time: 0 seconds. In the output shown here, I have highlighted the line which shows which build file was run, and I have highlighted the output from the echo task. As we learned from the error message which we received earlier, you can also use the -buildfile switch to select a particular build file: [D:\temp\bar]nant -buildfile:foo.build NAnt 0.85 (Build 0.85.1932.0; rc3; 4/16/2005) Copyright (C) 2001-2005 Gerry Shaw http://nant.sourceforge.net Buildfile: file:///D:/temp/bar/foo.build Target framework: Microsoft .NET Framework 1.1 Target(s) specified: talk talk: [echo] You ran foo.build BUILD SUCCEEDED Total time: 0 seconds. If you look at the highlighted elements in the output shown here, you can see that I used a simple command to select a particular build file. This technique requires a little more effort each time you run NAnt, but it is easy enough to wrap the NAnt command in a batch file. In the end, which technique you select is a matter of taste, and possibly a matter of convenience given a particular set of circumstances.. If you use the Windows Explorer to associated nant.exe with .build files, then you can also double click on a build file from the Windows GUI to run NAnt. It is also possible to integrate NAnt with many popular IDE’s. I generally choose to run NAnt files from the command prompt, but you should feel free to do whatever you find most convenient. I have found all three techniques useful at different times. #### Working with Config Files Now that we understand a little more about NAnt, it is time to move on to a discussion of using NAnt to read and write from sections of a .NET config file. Consider the following very simple app.config file for a .NET project: <?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings> <add key="AppName" value="TradeMaster" /> <add key="DatabaseName" value="Velocity" /> <add key="FtpAddress" value="localhost" /> </appSettings> </configuration> Suppose you want to change the value of the AppName tag from TradeMaster to TradeMonster. Here is a simple NAnt file that uses the xmlpoke task to make the change: <project name="ConfigChanger" default="configWrite"> <target name="talk"> <echo message="You ran default.build"/> </target> <target name="configWrite"> <xmlpoke file="config01/app.config" xpath="/configuration/appSettings/add[@key='AppName']/@value" value="TradeMonster"> </xmlpoke> </target> </project> The xmlpoke task shown here has three attributes: file, xpath and value: • The file attribute designates the name of the config file to access. In this case we are accessing a file called app.config which is in a directory called config01. In our case, the path to the directory would be: D:\temp\bar\config01\app.config. • The xpath attribute is an xsl statement designed to access a particular node of the xml based config file. • The value attribute is the new value of the node designated by the xpath statement. NOTE: Go to this link, to get to the complete docs on the xmlpoke task. ##### Thinking about XPath In this section I will talk briefly about XPath. If you know at least a little bit about XML files, and if you have at least heard an introduction to the technology called xsl, then you should be able to follow this section of the text. If not, then don’t be afraid to skip ahead to the next section of the text. xpath is a language designed to make it possible for you to single out a part of an XML file. The part you want to single out might be an attribute, a tag, an element, or a group of elements. In this case, we are interested in the value of a single attribute of a single element. You have already seen one way to specify the attribute value in XML: <configuration> <appSettings> <add key="AppName" value="TradeMaster" /> Consider the following code excerpt which slightly re-arranges the syntax shown above: <configuration> <appSettings> <add key="AppName" value="TradeMaster" /> Now let’s look again at our xpath statement: xpath="/configuration/appSettings/add[@key='AppName']/@value" Notice how the code uses slashes to dig down through the hierarchy of start tags from the outer configuration tag to the inner add tag, and then move on to the attribute named value. Before going on, take a moment to recall that each attribute in an xml file consists of two parts. First comes the name, and then an equals sign, and then the value associated with the name. In this case Microsoft has saddled us with syntax that is a bit confusing. The name of the attribute we care about is value and it has a value of "TradeMaster". Compare it with the first attribute, which has a name of key, and a value of AppName: <add key="AppName" value="TradeMaster" /> This is the way .NET config files are structured, and we have to work with the tools at hand. It turns out that there are multiple add nodes in this xml file. We use the following syntax to say that we want to talk about the add element that has an attribute called key with a value of AppName: [@key='AppName'] The ugly little @ symbol before the word key let’s us know that we are talking about an attribute. But we aren’t ultimately interested in the key attribute. Instead, we are focused on the attribute called value: /@value Again, we are digging down through a set of nested attributes which are separated by slashes. Recall that the @ symbol let’s use know that we are looking for an attribute. The name of this attribute is value. Look one more time at the portion of the XML file that interests us: <configuration> <appSettings> <add key="AppName" value="TradeMaster" /> In this code excerpt, the part of this XML file that is pointed at by our xpath statement is highlighted. Now that we have finally parsed our xpath statement and gotten down to the part of the xml based config file that interests us, we can look again at our xmlpoke statement from the NAnt file::  <xmlpoke file="Config01/app.config" xpath="/configuration/appSettings/add[@key='AppName']/@value" value="TradeMonster"> </xmlpoke> The very last line in our xmlpoke task says that we want to set the value of the attribute named value to the string "TradeMonster." To sum up: Our xmlpoke node tells NAnt to open up a particular config file, to search for a particular attribute of a particular element, and to set its value to the word "TradeMonster." To run this code, we go to the command prompt and type nant. [D:\temp\bar]nant NAnt 0.85 (Build 0.85.1932.0; rc3; 4/16/2005) Copyright (C) 2001-2005 Gerry Shaw http://nant.sourceforge.net Buildfile: file:///D:/temp/bar/default.build Target framework: Microsoft .NET Framework 1.1 Target(s) specified: configWrite configWrite: [xmlpoke] Found '1' nodes matching XPath expression '/configuration/appSetting s/add[@key='AppName']/@value'. BUILD SUCCEEDED Total time: 0 seconds. As usual, NAnt is very polite about providing us with plenty of useful feedback. You can use the -quiet option if you want less feedback from NAnt. When we are done, the config file should be changed: <?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings> <add key="AppName" value="TradeMonster" /> <add key="DatabaseName" value="Velocity" /> <add key="FtpAddress" value="localhost" /> </appSettings> </configuration> #### Reading with XmlPeek Let’s finish up this first section of our article by learning how to read from an XML file using the NAnt task called xmlpeek. Consider the following, improved version of our build file: <project name="ConfigChanger" default="configWrite"> <property name="appName" value="unknown"/> <target name="talk"> <echo message="You ran default.build"/> </target> <target name="configWrite"> <xmlpoke file="Config01/app.config" xpath="/configuration/appSettings/add[@key='AppName']/@value" value="TradeMonster"> </xmlpoke> </target> <target name="configRead"> <xmlpeek file="Config01/app.config" xpath="/configuration/appSettings/add[@key='AppName']/@value" property="appName"> </xmlpeek> <echo message="${appName}"/>
</target>

</project>

This file is similar to the one shown in previous sections of the text. We have, however, added two sections:

• At the top of the file there is a property called appName.
• At the bottom of the file there is a new target called configRead that contains an xmlpeek task.

The xmlpeek task is identical to the xmlpoke task, except that it reads instead of writes. In particular, the programmer should specify a property that will contain the value of the part of the XML file pointed to by the xpath statement:

<xmlpeek
file="Config01/app.config"
property="appName">
</xmlpeek>

The property portion of this xmlpeek task points at a property we declared called appName. At the beginning of the file, appName is initialized to contain a value of unknown:

<property name="appName" value="unknown"/>

After the configRead target has been called, the value of appName should be automatically set to the value of the part of the XML file designated by our xpath statement. If that is the case, then the echo task should print out the word TradeMaster or TradeMonster. The best way to see if it works is to go to the command prompt and try it out. In this case, we don’t want to execute the default target, but instead the one called configRead:

[D:\temp\bar]nant configRead
NAnt 0.85 (Build 0.85.1932.0; rc3; 4/16/2005)
http://nant.sourceforge.net

Buildfile: file:///D:/temp/bar/default.build
Target framework: Microsoft .NET Framework 1.1

[xmlpeek] Peeking at 'D:\temp\bar\Config01\app.config' with XPath expression '
[xmlpeek] Found '1' nodes with the XPath expression '/configuration/appSetting

BUILD SUCCEEDED

Total time: 0 seconds.

The two highlighted section of this output tell the story. The first highlight shows that we called NAnt with syntax specifying that it execute the configRead section of default.build:

nant configRead

The second highlighted area shows that our property has been changed from its default value of unknown, to a new value picked up from our XML file. In particular, the word TradeMonster is printed out for our delictation.

#### Summary

In this article you have learned how to work with multiple NAnt files, and how to use xmlpoke and xmlpeek to read and write to a particular area in an XML file. Much of the article focused on an introduction to the very simplest possible XPath syntax.

In the next article, you will see how to work with these basic tools to design a simple system for changing multiple parts of a .NET config file with a minimum of syntactical fuss. That section of the article will include details on calling one NAnt build file from another NAnt build file, and the specifics about how to pass information back and forth between the two files.

# The Need for Bad Software

Unless you happen to be Don Knuth, you have probably written bad software. But believe it or not, bad software is good for you.

One of the funniest blogs for developer is The Daily WTF. For normal people like my wife it is of course completely and utterly baffling, containing, as it does, words arranged in monospace fonts with punctuation where it shouldn’t be (sometimes with more punctuation than any text has a right to have), different lines indented in different ways, and if you’re lucky some words get to be printed in blue or red.

The Daily WTF’s premise is simple: developers enjoy a good laugh when we see badly written software. The laughter is usually accompanied by a fervent prayer muttered under our breath: "We hope by all that’s holy that we didn’t write it, and we pray that it isn’t part of the application we’re currently developing." The blog has a post a day that lampoons some source code, some interaction between a developer and other IT personnel, or some development-related happening.

Consider this saying: "You learn from your mistakes." Though a bit trite and clichéd, it does hold a grain of truth. Think back in time to a really awful bit of code you wrote. What happened when the inevitable bug report came in, and you investigated, and noted with horror what your younger self had written? You broke out in a sweat, your eyes dilated and you uttered the immortal acronym WTF, but in a decompressed form. Maybe you were able to cover it up, maybe it had to be written down in all its glory in the bug report’s commentary and then you had to go past people in the hallway who would fall silent and watch as you went by.

But I’ll bet you’ve never written code like that ever again.

Another example maxim: you only learn by doing. You know, you can read all the books and erudite exposition explaining how test-driven development helps you write better software, but you won’t internalize those lessons until you actually start writing tests. Until then it’s merely a nice thought experiment with no contact with reality. But how many times will you write bad software, or make the same coding mistake, or forget to check a fix in, before you start to wonder whether having a test suite could actually save your bacon? And guess what? Once you start with a unit test suite, you’ll be adding code to it all the time. Your code will get better. You willl stop making the same mistakes, (but make different ones and probably be able to fix them faster.) And most importantly, you’ll learn to rely on the tests that are run each time you check your code in.

You see, we do have a real need for bad software. It is only through bad software that we get better tools, better algorithms, better methodologies.

##### Server-side Validation

All business-level validations should be handled by model JavaBeans (or Enterprise JavaBeans) on the server. By placing the code in a central, logical location, you create a much more maintainable web application. Of course, this means that you frequently have a 2 tiered approach to validation: the client handles formatting and simple validations while the server code does the business level validation.

###### Forms and Validation with Struts

Again, Struts provides a nice illustration on how to design server-side validation in a flexible way. One of the common chores in web applications is the handling of forms. The JSP mechanism of automatically populating the fields of a Java bean with form post parameters goes a long way in reducing the tedious code that would have to be written otherwise. Struts has built on top of this mechanism to provide an easy way to handle populating beans in wizard style interfaces and handling validation.

When creating a Struts form, you have the option of creating a Struts form bean. This is a regular Java bean with typical accessors and mutators for the fields of the bean (and very little other code) that subclasses the org.apache.struts.action.ActionForm base class. Note that these beans should not connect to a database to populate themselves or provide a lot of other infrastructure code. They should be very lightweight classes that basically encapsulate entity information. Other beans should handle persistence and other duties. In fact, it is typical to have one bean that acts as a collection of the entities represented by a Struts form bean (like the ScheduleBean used in the Action class discussed above).

One of the additional sections in the struts-config XML document allows you to declare a class as a form-bean. Look at the top of the sample struts-config document above. A form-bean declaration allows you to specify a name for the form bean and map that to a specific class (in this case, schedule.ScheduleItem). In the action-mapping section of the config file, you can automatically associate a form bean with an action. Notice the "add" action in the config file. The additional "name" parameter allows you to specify a form bean to use with that action. Once you have a form bean associated with an action, Struts will perform the following services for you before invoking the action method:

• Check the user’s session for an instance of the bean under the name specified in the struts-config file. If one doesn’t yet exist, Struts creates one and adds it to the user’s session
• For every request parameter that matches one of the setXXX methods of the bean, the appropriate set method will be called
• The updated ActionForm bean is passed to the Action as a parameter

This is similar to the standard JSP behavior of handling request parameters that map to fields of a JavaBean. However, Struts performs more services for you. Struts also comes with a collection of custom JSP tags, split into 4 categories. One of the categories allows you to replace standard HTML tags for input elements with "smarter" Struts tags. If you use the Struts HTML tags, it will also automatically populate the input fields on the form from the ActionForm whenever the page is visited. This makes it really easy to handle wizard style interfaces. Notice that an ActionForm bean doesn’t have to correspond to a single page. More typically, it corresponds to a single set of user information. So, you can have an ActionForm that spans multiple pages. Using the Struts HTML tags, the input fields the user has already filled in will be automatically populated as the user moves back and forth between the pages of the wizard. For an example of a JSP that uses the custom tags, see the following listing.

Listing 10: An HTML form using custom Struts tags

<%@ taglib uri="/WEB-INF/struts-html.tld"
prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld"
prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts.tld"
prefix="struts" %>
<jsp:useBean id="scheduleItem" scope="request"
class="schedule.ScheduleItem" />
<jsp:useBean id="scheduleBean" scope="page"
class="schedule.ScheduleBean" />
<% pageContext.setAttribute("eventTypes",
scheduleBean.getEventTypes()); %>
<HTML>
<TITLE>
ScheduleEntryView
</TITLE>
<BODY>
<H1>
</H1>
<hr>
<html:errors/>
<table border="0" width="30%" align="left">
<tr>
<th align="right">
<struts:message key="prompt.duration"/>
</th>
<td align="left">
<html:text property="duration"
size="16"/>
</td>
</tr>
<tr>
<th align="right">
<struts:message key="prompt.eventType"/>
</th>
<td align="left">
<html:select property="eventType">
<html:options collection="eventTypes"
property="value"
labelProperty="label"/>
</html:select>
</td>
</tr>
<tr>
<th align="right">
<struts:message key="prompt.start"/>
</th>
<td align="left">
<html:text property="start"
size="16"/>
</td>
</tr>
<tr>
<th align="right">
<struts:message key="prompt.text"/>
</th>
<td align="left">
<html:text property="text"
size="16"/>
</td>
</tr>
<tr>
<td align="right">
<struts:submit>
<bean:message key="button.submit"/>
</struts:submit>
</td>
<td align="right">
<html:reset>
<bean:message key="button.reset"/>
</html:reset>
</td>
</tr>
</table>
</html:form>
</BODY>
</HTML>

This listing shows some other features of Struts tags as well. One of the automatic features of Struts is form validation. The struts-config file allows you to flag an action associated with a form bean to enable validations. This assumes that you have added a validation method to your form bean class. A sample validation method is shown here.

Listing 11: The validate() method of a form bean.

public ActionErrors validate(
ActionMapping actionMapping,
HttpServletRequest request) {
ActionErrors ae = new ActionErrors();
if (duration < 0 || duration > 31) {
"error.invalid.duration", "8"));
}
if (text == null || text.length() < 1) {
new ActionError("error.no.text"));
}
return AE;
}

The validate() method is automatically called by the Action object after the population of the form bean fields but before any of the code in the Action is performed. If the validate() method returns either null or returns an empty ActionErrors collection, processing of the Action continues normally. If errors have been returned from validate(), Struts will automatically return the user to the input form, repopulate the fields from the form bean, and print out a list of the reported errors at the top of the page. For an example of this, see the figure below. This is a Struts form where the user has put in a negative duration and left the Text field blank. The errors listed at the top are automatically generated via the validate() method and the <html:errors/> tag at the top of the file (the position of this tag determines where the errors will appear on the page).

You will also notice that the error messages returned by the validate method aren’t the messages that appear on the page. The strings added in the ActionError constructor map to messages in a java.util.Properties file. This properties file is automatically referenced by Struts (this is one of the parameters of the ActionServlet), and allows for easy separation of the messages in the application from the code. This means that the text of the message can be easily changed without recompiling the application. This is also how Struts handles internationalization. Struts can be set up to look for a properties file that matches the locale encoding of the request to automatically provide text messages in the appropriate language. This is another service provided by the HTML tags. Notice in Listing Five that the input text references fields in the properties file.

###### If You Must Do Client-side Validation for Business Rules…

There are some web applications that simply must provide the instant feedback that you can only get with Javascript and client-side validation. In those cases, there is a solution. Because you must embed the business rules in Javascript, you should create a method on your model bean the outputs the necessary Javascript for the validation. This way, the model bean is still responsible for the validation, it just delegates it to the presentation layer. This still leaves the validation code itself in the business layer, where it can be easily changed.

Here is a simple example. In a model class named Order, the JavaScript validation for ensuring that a credit card field has a numeric value in it.

Listing 12: Model class that contains JavaScript to validate entry

public class Order implements Serializable {
private static final String JS_CC_FORM_VALIDATION =
"<script>" +
"   function verify(e) {" +
"       if (e.value == null || isNaN(parseInt(e.value))) {" +
"           alert('Field must be numeric');" +
"           e.focus();" +
"           return false;" +
"       }" +
"   }" +
"</script>";
public String getFormValidationForCC() {
return JS_CC_FORM_VALIDATION;
}
//... more methods follow

To embed this code in the view, you can use the typical JSP tags to generate the code into the view.

Listing 13: JSP code that pulls JavaScript from the model for validations

<%-- get JavaScript validation code from Order class --%>
<jsp:getProperty name="order" property="formValidationForCC"
/>
<form action="CheckOut" method="post" onSubmit='verify
(this.ccExp)'>
Credit Card # <input type="text" name="ccNum">
Credit Card Type <select name="ccType">
<option value="Visa">Visa</option>
<option value="MC">MC</option>
<option value="Amex">AMEX<option>
</select>
Credit Card Exp Date <input type="text" name="ccExp" >
<input type="submit" value="Check out">
</form>

As you can see, this allows you to keep the business rules of the application in the model class but still get the benefits of client-side validation.

#### Caching using the Flyweight Design Pattern

The Flyweight design pattern appears in the Gang of Four book, which is the seminal work on patterns in software development. The pattern uses sharing to support a large number of fine-grained object references. With the Flyweight strategy, you keep a pool of objects available and create references to the pool of objects for particular views. This pattern uses the idea of canonical objects. A canonical object is a single representative object that represents all other objects of that type. For example, if you have a particular product, it represents all products of that type. In an application, instead of creating a list of products for each user, you create one list of canonical products and each user has a list of references to that list.

A typical e-commerce application is designed to hold a list of products for each user. However, that design is a waste of memory. The products are the same for all users, and the characteristics of the products change infrequently. This figure shows the current architectural relationship between users and the list of products in the catalog.

Each user holds a list of products.

The memory required to keep a unique list for each user is wasted. Even though each user has his or her own view of the products, only one list of products exists. Each user can change the sort order and the catalog page of products he or she sees, but the fundamental characteristics of the product remain the same for each user.

A better design is to create a canonical list of products and hold references to that list for each user.

In this scenario, each user still has a reference to a particular set of products (to maintain paging and sorting), but the references point back to the canonical list of products. This main list is the only actual product object present in the application. It is stored in a central location, accessible by all the users of the application.

##### Flyweight considerations

The effectiveness of the Flyweight pattern as a caching mechanism depends heavily on certain characteristics of the data you are caching:

• The application uses a large number of objects.
• Storage (memory) cost is high to replicate this large number for multiple users.
• Either the objects are immutable or their state can be made external.
• Relatively few shared objects may replace many groups of objects.

The application doesn’t depend on object identity. While users may think they are getting a unique object, they actually have a reference from the cache.

One of the key characteristics enabling this style of caching is the state information in the objects. In the previous example, the product objects are immutable as far as the user is concerned. If the user is allowed to make changes to the object, then this caching scenario wouldn’t work. It depends on the object stored in the cache being read-only. It is possible to store non-immutable objects using the Flyweight design pattern, but some of their state information must reside externally to the object.

It is possible to store the mutable information needed by the reference in a small class that is associated to the link between the Flyweight reference and the Flyweight object. A good example of this type of external state information in an ecommerce application is the preferred quantity for particular items. This is information particular to the user, so it should not be stored in the cache. However, there is a discrete chunk of information for each product. This preference (and others) would be stored in an association class, tied to the relationship between the reference and the product. When you use this option, the information must take very little memory in comparison to the Flyweight reference itself. Otherwise, you don’t save any resources by using the Flyweight.

The Flyweight design pattern is not recommended when the objects in the cache change rapidly or unexpectedly. It would not be a suitable caching strategy for the ecommerce application if the products changed several times a day. This solution works best when you have an immutable set of objects shared between most or all of your users. The memory savings are dramatic and become more pronounced the more concurrent users you have.

# On micro-optimizations

What’s a micro-optimization, you may ask? It’s applying a local-in-scope rule about optimization to your code without actually testing to see if it makes any difference to the performance of your application as a whole. Micro-optimizations are generally cast as never-to-be-broken rules, or even as items in some coding standards document.

Examples are easy to find: always using for instead of foreach, appending to a StringBuilder object instead of string concatenation, avoiding small methods to minimize the call time. Or, if you are a Delphi Win32 developer, never using TCollection, not using interfaces because of the reference counting, using other optimization tricks and tips.

Now, before you start huffing and puffing, I’m not advocating abandoning these optimizations, or saying that they are inherently evil, or anything like that. All I’m saying is that you should initially write code as clearly as possible. That implies that your code should be readable, simple and understandable. After all, your code gets written just the once, and then will be read many, many times.

Concentrate, therefore, on writing the clearest, simplest code that satisfies the requirements. Writing clear code gives you the best chance of creating provably correct software and of creating code that is easier to optimize. Writing clear code provides the best opportunity for enhancing maintainability. Far more money is spent on software maintenance than is ever spent on the original code. Clear code is generally more flexible and better able to adapt to future needs and changes. Consider using refactorings guided by software metrics to simplify your code. Consider using your skills as a developer to identify and remove code smells.

And it’s only after your code is written that you get to profile it to test its performance within the application. Only then do you get to analyze the hot spots in your application as a whole. Only then do you get to formulate a thesis ("replacing this simple-to-read foreach with a slightly harder to read for loop will improve the performance of my application as a whole") and then test it with the real application. Only then should you accept code changes that have a measurable change in your application’s performance. Only then should you reject failed theses and revert your code to the simpler-to-read version.

Of course, when you profile, don’t just profile the speed performance of your application. Profile the space requirements too, the memory pressure on the heap (the number and sizes of objects created and destroyed), the stress on the virtual memory system.

And remember that in order to refactor your code you must have unit tests to ensure that you don’t break functionality as you polish the performance.