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

Warning: mysql_real_escape_string(): A link to the server could not be established in /home/dh_kxiiuj/codefez.com/wp-content/plugins/tla/textlinkads.php on line 641
Source Code | CodeFez

Creating Custom NAnt Tasks

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.

NAnt Tasks

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)
Copyright (C) 2001-2005 Gerry Shaw
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.

Sometimes the built in tasks do not provide all the functionality you might need. In that case, you can create a custom task of your own. The purpose of this article is to show you the simple steps necessary to create your own custom task. After you have created the task, it will be saved to a DLL, where it can be easily reused in other projects.

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>
    <add key="AppName" value="TradeMaster" />
    <add key="DatabaseName" value="Velocity" />
    <add key="FtpAddress" value="localhost" />
  </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;


namespace NAnt.Examples.Tasks 
{
	[TaskName("configtask")]
	public class ConfigTask : Task 
	{   
		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.Add(fileNameProperty, fileName);

			project.Properties.Remove(attributeNameProperty);
			project.Properties.Add(attributeNameProperty, attributeName);

			project.Properties.Remove(valueNameProperty);
			project.Properties.Add(valueNameProperty, valueName);
		}

		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");
			DoFileNames(project, "AppName", "TradeMaster");
			DoFileNames(project, "FtpAddress", "localhost");
		}

		// Override the ExecuteTask method.
		protected override void ExecuteTask() 
		{
			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;


namespace NAnt.Examples.Tasks 
{
	[TaskName("configtask")]
	public class ConfigTask : Task 
	{   
		// Override the ExecuteTask method.
		protected override void ExecuteTask() 
		{
			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">

	
	<property name="libName" value = "bin\ConfigTask.dll"/>

	<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>
                <include name="ConfigTask.cs"/>
            </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 -->
        <configtask/>
    </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>
                <include name="ConfigTask.cs"/>
            </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. -->
	<configtask/>
</target>

As you can see, there is a specific task, called loadtasks, which is designed to load an assembly into memory. Once it is loaded, we are free to call our task:

 <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;

namespace NAnt.Examples.Tasks 
{
	[TaskName("configtask")]
		public class ConfigTask : Task 
	{
		private string _fileName;

		[TaskAttribute("fileName", Required=true)]
		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.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 RunConfig(Project project) 
		{   
			project.Execute("setValues");
			DoFileNames(project, "DatabaseName", "Zendo");
			DoFileNames(project, "AppName", "TradeMaster");
			DoFileNames(project, "FtpAddress", "localhost");
		}

		protected override void ExecuteTask() 
		{   
			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;

[TaskAttribute("fileName", Required=true)]
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/>

Now we add our new TaskAttribute to the XML which calls out task:

<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"
			xpath="/configuration/appSettings/add[@key='AppName']/@value"
			value="TradeMonster">
		</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>
    <add key="AppName" value="TradeMaster" />
    <add key="DatabaseName" value="Velocity" />
    <add key="FtpAddress" value="localhost" />
  </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"
			xpath="/configuration/appSettings/add[@key='DatabaseName']/@value"
			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>
    <add key="AppName" value="TradeMonster" />
    <add key="DatabaseName" value="Zen" />
    <add key="FtpAddress" value="localhost" />
  </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.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>

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");
		DoFileNames(project, "AppName", "TradeMaster");
		DoFileNames(project, "FtpAddress", "localhost");
	}

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");
		DoFileNames(project, "AppName", "TradeMonster");
		DoFileNames(project, "FtpAddress", "ftp.elvenware.com");
	}

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>
		<add key="AppName" value="TradeMaster" />
		<add key="DatabaseName" value="Zen" />
		<add key="FtpAddress" value="localhost" />
	</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>
		<add key="AppName" value="TradeMonster" />
		<add key="DatabaseName" value="Velocity" />
		<add key="FtpAddress" value="ftp.elvenware.com" />
	</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");
	DoFileNames(project, "AppName", "TradeMaster");
	DoFileNames(project, "FtpAddress", "localhost");
}

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.Add(fileNameProperty, fileName);

	project.Properties.Remove(attributeNameProperty);
	project.Properties.Add(attributeNameProperty, attributeName);

	project.Properties.Remove(valueNameProperty);
	project.Properties.Add(valueNameProperty, valueName);
}

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"
	xpath="/configuration/appSettings/add[@key='AppName']/@value"
	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)
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: configRead


configRead:

  [xmlpeek] Peeking at 'D:\temp\bar\Config01\app.config' with XPath expression '
/configuration/appSettings/add[@key='AppName']/@value'.
  [xmlpeek] Found '1' nodes with the XPath expression '/configuration/appSetting
s/add[@key='AppName']/@value'.
     [echo] TradeMonster

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.

Think about it another way: it took several iterations of really bad software before Microsoft launched their Trustworthy Computing initiative. And it took them awhile to see the value in designing the CLR. The CLR demonstrates that it is harder (but not impossible) to write unsecure code with managed code and the .NET framework than with the C run-time library and pointers galore. It took an analysis of Diebold’s bad voting machine software to make us realize that hanging chads were the good old days. It takes bad software to crash a Mars probe into the planet and thereby waste $250 million and nine months in one glorious thud. It takes bad software for us all to appreciate that it’s new software we like writing, but that the steady money comes from software maintenance.

Bad software is everywhere; we have to live with it. It permeates the programs we use every day, it infuses the components we use, it pervades the society we live in. It forces us, as developers, to strive to better ourselves and to write better code. (If it doesn’t have this effect on you, then maybe you should go do something else!)

It takes bad software to make us appreciate the good software. Best of all, it gives us a good laugh every day!

The Big-Oh notation

When we compare algorithms in order to select one to use, we often need an understanding of their performance and space characteristics. Performance is important because, well, we’re always interested in raw speed; and space is important because we are always on the lookout for algorithms that don’t waste memory. Of course, there are other considerations too. For example, we might want to know how easy it is to implement algorithm X or algorithm Y. Yet most of the time we are primarily interested in performance and space characteristics.

We’ll talk about space considerations in a later article; for now, we’ll consider how to compare the performance of algorithms.

When comparing performance we need a compact notation to express its characteristics. For instance, it is awkward to say "the performance of algorithm X is proportional to the number of items it processes, cubed," or something equally as verbose. Fortunately Computer Science has a solution to this problem; it’s called the big-Oh notation.

We begin by running a series of profiling experiments to analyze the performance characteristics of the algorithm in which we’re interested. (If we’re Don Knuth, we can also try to derive the characteristics mathematically from first principles.) If we are lucky, the results of these profiling runs allow us to work out the mathematical function of n, the number of items, to which the time taken by the algorithm is proportional, and then say that the algorithm is an O(f(n)) algorithm, where f(n) is the mathematical function we determined. We read this as "big-Oh of f(n)", or, less rigorously, as "proportional to f(n)."

For example, if we timed experiments on a sequential search through an array for different numbers of items in the array, we would find that it is a O(n) algorithm. Binary search, on the other hand, we’d find out to be a O(log(n)) algorithm. Since log(n) < n, for all positive n, we could say that binary search is always faster than sequential search since the time taken would always be smaller. (However, in a moment, I shall be dishing out a couple of warnings about taking conclusions from the big-Oh notation too far. Be warned.)

Suppose that by experimentation we work out that Algorithm X is O(n2 + n), in other words, the time it takes to run is proportional to n2 + n. By "proportional to" we mean that we can find a constant k such that the following equation holds:

TimeTaken = k * (n2 + n)

Now, in general, the value of k doesn’t really affect our intuition of the performance of Algorithm X. Yes, higher values of k result in slower performance, but the important bits are within the parentheses, the n squared and the n. Increasing n doesn’t affect k; it’s constant, remember. In fact, knowing this, we can see that multiplying the mathematical function inside the big-Oh parentheses by a constant value has no effect. For example, O(3 * f(n)) is equal to O(f(n)); we can just take the ‘3’ out of the big-Oh notation and multiply it into the outside proportionality constant, the one we can conveniently ignore.

(The same goes for adding a constant inside the big-Oh parentheses; for large n, O(n + 42) is the same as O(n).)

If the value of n is large enough when we test Algorithm X, we can safely say that the effects of the "+ n" term are going to be swallowed up by the n2 term. In other words, providing n is large enough, O(n2 + n) is equal to O(n2). And that goes for any additional term in n: we can safely ignore it if, for sufficiently large n, its effects are swallowed by another term in n. So, for example, a term in n2 will be swallowed up by a term in n3; a term in log(n) will be swallowed up by a term in n; and so on. Note that this only applies when we’re adding or subtracting terms, we can’t ignore multiplying or dividing terms in the same manner (unless the term is constant, as we’ve shown).

This shows that arithmetic with the big-Oh notation is very easy. Let’s, for argument’s sake, suppose that we have an algorithm that performs several different tasks. The first task, taken on its own, is O(n), the second is O(n2), the third is O(log(n)). What is the overall big-Oh value for the performance of the algorithm? The answer is O(n2), since that is the dominant part of the algorithm, by far.

But, having said that, here comes the warning I was about to give you before about drawing conclusions from big-Oh values. Big-Oh values are representative of what happens with large values of n. For small values of n, the notation breaks down completely; other factors start to come into play and swamp the general results. For example, suppose we time two algorithms in an experiment. We manage to work out the two performance functions from our statistics:

Time taken for first = k1 * (n + 100000)
Time taken for second = k2 * n2

The two constants k1 and k2 are of the same magnitude. Which algorithm would you use? If we went with the big-Oh notation, we’d always choose the first algorithm because it’s O(n). However, if we actually found that in our applications n was never greater than 100, it would make more sense for us to use the second algorithm.

So, when you need to select an algorithm for some purpose, you must take into account not only the big-Oh value of the algorithm, but also its characteristics for the average number of items (or, if you like, the environment) for which you will be using the algorithm). Again, the only way you’ll ever know you’ve selected the right algorithm is by measuring its speed in your application, for your data, with a profiler. Don’t take anything on trust from an author like me; you should measure, time, and test.

There’s another issue we need to consider as well. The big-Oh notation generally refers to an average case scenario. In our sequential versus binary search thought experiment, if the item for which we were looking was always the first item in the array, we’d find that sequential search would always be faster than binary search — we would succeed in finding the element we wanted after only one test. This is known as a best case scenario and is O(1). (Big-Oh of 1 means that it takes a constant time, no matter how many items there are.)

If the item which we wanted was always the last item in the array, the sequential search would be a pretty bad algorithm. This is a worst case scenario and would be O(n), just like the average case.

Although binary search has a similar best case scenario (the item we want is bang in the middle of the array and is found at the first shot), its worst case scenario is still much better than that for sequential search.

In general, we should look at the big-Oh value for an algorithm’s average and worst cases. Best cases are usually not too interesting — we are generally more concerned with what happens "at the limit," since that is how our applications will be judged.

In conclusion, we have seen that the big-Oh notation is a valuable tool for us to characterize various algorithms that do similar jobs. We have also discussed that the big-Oh notation is generally valid only for large n, for small n we are advised to take each algorithm and time it. Also, the only way for us to truly know how an algorithm will perform in our application is to time it. Don’t guess, use a profiler.

In the second part of this article, you will learn about space and memory considerations and how those factors effect the selection of algorithms.

Readability Matters: It’s Not The Language

It’s not the language that makes code more readable, it’s how you write the code. It’s how you decompose the problem space into classes and methods in those classes. It’s how you decouple the classes. It’s whether your language uses a garbage collector or not (and if not, whether you’ve been consistent in freeing memory and how you free it). It’s consistency in how you write similar code. It’s in keeping the reader familiar with your code.

Most readers of your code are going to be reading it from the vantage point of knowing the language you’re using. Some readers will be reading it knowing just enough about the language to be dangerous. And then some readers will be reading it from a vantage point of complete ignorance and trying to match the code to a language they know better.

For an extreme example for most of my readers, here’s some Haskell code:

insert :: Int -> [Int] -> [Int]
insert n [] = [n]
insert n (x:xs)
   | n <= x   = n:x:xs
   | otherwise  = x:insert n xs

Is this readable? To a C#, Java or Delphi programmer, heck no! To a Haskell programmer, yep, it’s pretty simple. Here’s the roughly equivalent Delphi code as I would write it:

procedure Insert(n : integer; aList : TList);
var
  i : integer;
begin
  for i := 0 to pred(List.Count) do
    if (n <= integer(List[i])) then begin
      List.Insert(i, pointer(n));
      Exit;
    end;
  List.Add(pointer(n));
end;

And here it is in C#:

public static void Insert(int n, ArrayList list) {
  for (int i = 0; i < list.Count; i++) {
    if (n <= (int) list[i]) {
      list.Insert(i, n);
      return;
    }
  }
  list.Add(n);
}

So, the Haskell code inserts an integer value in a sorted array or list of integers. Which is more readable? Answer: what you are more familiar with.

(To those not familiar with Haskell, you can read the above code like this. Line 1: insert is defined as a function that takes an integer and an array of integers and produces an array of integers. Line 2: If the array of integers is originally empty, return an array that just contains one element, n, the item we’re inserting. Line 3: if the array is not empty, it’ll consist of the first element x and the remaining part of the array xs, so let’s define how that works in the indented lines underneath. Line 4: if the item we’re inserting, n, is less than or equal to x, return the array formed from n, x, and the rest of the array. Line 5: otherwise the answer is obtained by prepending x to the result of inserting n in the remaining part of the array, xs (a recursive call, in other words).

As you can see my equivalent Delphi and C# code is not the same at all since it returns the same list with the new item in it, not a completely different list. I cheated (hey, I’m writing this article and I’m allowed to!). See how you can do in writing a better Delphi/C# equivalent that does what the Haskell code does. The C# version should be very easy; the Delphi version less so since the question to consider is this: what happens to the TList you pass in? Who frees it? Should this routine do so? Haskell and C# are garbage collected and you don’t have to worry about it. Delphi (at least the Win32 version) is not and so you have to consider adding a boolean parameter perhaps to free the original list. The code will become less readable.)

Do you favor multi-page, big methods? Your code is less readable. Do you have code that indents more than, oh, say, twice? Your code is less readable. Do you have methods with more than, say, three local variables? Your code is less readable. Do you regularly write methods with more than three parameters? It’s harder to read and understand and use. Do you have if or do statements with more than two conditions perhaps? Your code is automatically awful to read. Do you ignore refactoring possibilities? Your code is less easy to read. Do you use a lot of comments? Obviously your code is not readable since you are having to explain it. Do you leave the auto-generated names for controls on your forms (Button1, et al)? Your code is not readable. Do you favor single-letter names for identifiers, even for variables that are not counters? Your code is harder to read.

Do you have to work hard at making your code properly indented? You need a new IDE that formats your code for you. Do you read code in a program that doesn’t do syntax highlighting? Get an IDE that does for the language you’re reading.

Do you not use accepted coding patterns for your particular language when writing code, but instead use something unfamiliar? Your code will be nigh on impossible to read. Do you like trying to optimize your code as you write it without running a profiler instead of writing the most obvious thing? Your code will probably be slower, and harder to read to boot.

Being someone who writes algorithm articles, my research tends to throw out code in many different languages: C, Java, C++, Ruby, Haskell. I’m so glad when the writer has taken the care to make his code readable, no matter which language he uses.

In essence, writing readable code is a high-level, design-like activity. It’s usually not about the nitty-gritty syntax details like block delimiters or where variables are declared. It’s about how we structure our code.

Comments please?

In the old days (like about 3 years ago), I used to comment my code quite a bit. These days I don’t; it’s rare that I write a comment. Why? Here are some possibilities:

  1. I’ve got lazy in my old age.
  2. I inadvertently made comments display as white on white so I can’t see them any more. Why write them if I can’t see them?
  3. I’m of the firm belief that anyone who has to read my code has to be a Zen master. Since Zen masters reach an understanding of code that’s far deeper than mere mortals, it would aggravate them to have one-liners explaining it all.
  4. I’m so paranoid about the meaning of my code and comments drifting apart that I dare not  write comments any more.
  5. My code is now so simple it doesn’t need explanation. It is "self-documenting".

Now, I’m sure you’re all putting up your hands saying "Number 1". Wrong, sorry. Of these possibilities, the answer is the last one, number 5. To which I’m sure there are some who are saying "Yeah, sure, that’s an excuse for number 1".

But consider this. I love using refactoring tools to organize my code (I’ve been using C# Refactory for a long while in VS, and am just getting to know Delphi 2005’s refactoring tools). I write my code in a Test-Driven Development (TDD) manner. I think and design and write in small steps with unit tests to make sure I don’t go astray.

My code is naturally simpler than I ever used to write.

But what’s that to do with writing comments? Think about why you need to write comments. Perhaps you have a long method that’s difficult to grasp as you scan it (maybe it’s so long that it goes over several pages on the screen). In that case you have to write comments as some kind of "headers" within the "text" so that it breaks up the flow into manageable chunks, much as a book is divided into chapters, or an article is divided into sections.

In that case, I’d have to say that the method is too long. It should be broken up into smaller methods, into separate classes, or whatever. I’ve just written an article for The Delphi Magazine that explores how to break up a state machine written as a huge case statement with a case block per state. In the article, I describe how to break the code up into into several classes, each of which is simple to understand. Martin Fowler, in his book Refactoring, explores strategies for changing such code.

In long methods, the comment that describes the functionality of a block of code indicates that the block of code should be a separate method. A comment like "// Print the header block" which is followed by a bunch of code that prints the various parts of a header should be extracted to a new method called PrintHeaderBlock. Suddenly the method name describes what it does and the comment is superfluous. This is a simple example of self-documenting code.

Sometimes comments explain what a method does. I’d counter with either (1) the method is badly named (compare with the previous refactoring), or (2) the method does too much — it does several things, each of which should be done by a separate method. In fact the "badly-named method" is a very common error, or anti-pattern.

So when do I use comments?

  1. To explain an algorithm that may be obscure.
  2. To explain why a funky bit of code is used instead of an expected implementation. This can happen when the funky code is more efficient.
  3. To explain what fields are used for (although this could fall under the "bad-name" exception), what the items in an enumeration are used for, and so on. In general, though, I avoid them.

Take a look at your code. Are you explaining your code in comments instead of refactoring your code to something simpler so that it becomes self-documenting?

J2EE Design Strategies Part IV

Enterprise Java Beans

Fine-grained vs. Coarse-grained Entities

One of the design patterns discussed by the J2EE tutorials from Sun is this topic of fine-grained vs. coarse-grained entities. The issue here is one of client access. Generally, you want to keep the amount of round-trips to the application server as small as possible. Shuttling data over a network connection in a distributed application is an expensive operation in terms of time. In general, you should avoid creating many small entity beans and accessing them directly from the client. For example, if you have a customer entity in your application, the customer likely has an address (or many addresses). You should not create an Address entity to handle addresses. Instead, you should create an Address dependent object (also known as a value object). A dependent object is a simple Java class that encapsulates information and typically consists of only accessors and a constructor.

To access a Customer’s address, the customer entity has a method that returns an Address dependent object to you. If Address was modeled as an entity bean, you would have to access it through its remote reference just as you do Customer. By passing back a dependent object, you can cut down on the number of remote method calls you must make (for example, for all the fields in the address). This is what is meant by coarse-grained objects.

Here is an example of a dependent object for address:

Listing 14: Example of an address value object

import java.io.Serializable;
public class Address implements Serializable {
    private String addr1;
    private String addr2;
    private String city;
    private String state;
    private String zip;
    public Address(String addr1, String addr2, String city, String state,
            String zip) throws ValidationException {
        if (zip.length() < 5 || zip.length() >10) {
            throw new ValidationException("Zip code format error");
        }
        this.addr1 = addr1;
        this.addr2 = addr2;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }
    public String getAddr1() {
        return addr1;
    }
    public String getAddr2() {
        return addr2;
    }
    public String getCity() {
        return city;
    }
    public String getState() {
        return state;
    }
    public String getZip() {
        return zip;
    }
}

Dependent objects also provide a good place to house simple validation rules. In the example above, the constructor throws a ValidationException if the zip code is not formatted correctly. Note that all such code must appear in the constructor because there are no set methods (more about this shortly).

Another variation on this theme is to create bulk accessors and mutators. In this model, if you need to populate many of the fields of an entity, create a mutator that takes a value object as the parameter and make a single call, passing an instantiated value object. This way, you can make a single remote call instead of several.

Here is an example of a bulk accessor and mutator for Credit Card data.

Listing 15: Using bulk accesors and mutators

Credit Card Data class

public class CreditCardData implements Serializable {
    private String number;
    private String type;
    private String expirationDate;
    public CreditCardData() {
    }
    public CreditCardData(String number, String type, String expDate) {
        this.number = number;
        this.type = type;
        this.expirationDate = expDate;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getType() {
        return type;
    }u
    public void setExpirationDate(String expirationDate) {
        this.expirationDate = expirationDate;
    }
    public String getExpirationDate() {
        return expirationDate;
    }
 //-- more methods follow...
}

EJB using bulk accessors and mutators

public class OrderBean implements EntityBean {
    EntityContext entityContext;
    public String ccNumber;
    public String ccType;
    public String ccExpiration;
    public CreditCardData getData() {
        return new CreditCardData(ccNumber, ccType, ccExpiration);
    }
    public void setData(CreditCardData ccData) {
        ccNumber = ccData.getNumber();
        ccType = ccData.getType();
        ccExpiration = ccData.getExpirationDate();
    }
    //-- simple accessors
    public void setCcNumber(String ccNumber) {
        this.ccNumber = ccNumber;
    }
    
    public String getCcNumber() {
        return ccNumber;
    }

Immutable Value Objects

If you are using value objects (see the item above), you should ensure that they are immutable. Here’s why. If your value object is mutable (in other words, has mutator methods) and you pass a value object back from an entity, the client can call the setXXX() methods on the value object. However, the client is only changing their copy of the value object, not the values on the server. Because value objects are not remote objects, changes to the copy passed to the client will not be reflected on the server. So, to make sure this cannot happen, you should always make your value object immutable. If the user wants to make changes, they must create a brand new object instance and pass it back to the entity bean through one of it’s mutator methods.

Here is an example of changing the city of an address.

Listing 16: Changing the value of a dependent object

    Address a = ejbRef.getAddress();
    String newCity = "Atlanta";
    Addres newAddress = new Address(a.getAddr1(), a.getAddr2(), newCity,
            a.getState(), a.getZip());
    ejbRef.setAddress(newAddress);

Writing Proper Standard Methods for PrimaryKeys

This topic actually pertains to J2SE as well as J2EE. However, it is particularly important in the EJB context. Every primary key class must include both overridden equals() and hashCode() methods. However, creating these methods correctly is not a trivial manner.

equals()

To create a correct equals() method, you must adhere to the following conditions (taken from the J2SE specification):

  • It is reflexive: for any reference value x, x.equals(x) should return true.
  • It is symmetric: for any reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the object is modified.
  • For any non-null reference value x, x.equals(null) should return false.

Let’s investigate the implications of the above requirements. First, the method must be reflexive.

Reflexive

This requirement says that the object must equal itself. If you somehow violated this rule, then when you add this object to an unordered Collection, it would allow you to add it again. You generally shouldn’t have to worry about this property.

Symmetric

This property implies that two objects must agree with each other as to whether they are equal or not. This is most common when you override class, including some overridden nontrivial behavior, and want to still include an equality check with the parent class.

Consider the following class, representing an unsigned integer.

Listing 17: Example of a class with a well intentioned but broken equals() method.

public final class UnsignedInteger {
    private Integer uInt;
    public UnsignedInteger(Integer i) {
        if (i == null) {
            throw new NullPointerException();
        }
    }
    //-- broken equals()
    public boolean equals(Object o) {
        if (o instanceof UnsignedInteger) {
             return ((UnsignedInteger)o).uInt.equals(uInt);
        }
        if (o instanceof Integer) {
            return uInt.intValue() == (Math.abs(((Integer) o).intValue()));
        }
        return false;
    }
}

The problem with this class is that it is trying to interact with the Integer class. This violates symmetry because the Integer class knows nothing about this class, and will obviously never indicate that it is equal with any instance of an UnsignedInteger. To fix this problem, we need only remove the reference to the Integer class from the equals() method. In other words, this class should only try to determine if equality exists between two instances of this class.

Transitive

The third requirement states that is object a is equal to b, and b is equal to c, then a must be equal to c. Here is an example of a violation of this principle. In the listing below, we have created a simple immutable point class.

Listing 18: A simple immutable point class.

public class Point2D {
    private int x;
    private int y;
    public Point2D(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public boolean equals(Object o) {
        if (!(o instanceof Point2D)) {
            return false;
        }
        Point2D p = (Point2D) o;
        return p.x == x && p.y == y;
    }

    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

Now, we need to extend this class to account for 3D points.

Listing 19: A simple immutable 3D point class.

public class Point3D {
    private int z;
    public Point3D(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }
}

Is it possible to create a correct equals() method for this class? Consider this first pass.

Listing 20: First (incorrect) pass at an equals() method.

    //-- violates symmetry
    public boolean equals(Object o) {
        if (!(o instanceof Point3D)) {
            return false;
        }
        Point3D p3 = (Point3D) o;
        return super.equals(o) && p3.z == z;
    }

The problem is that you might get different results if you compare a Point2D with a Point3D — 2D ignores the z dimension and 3D fails because the class type is always incorrect. One attempt to fix this would have the Point3D try to ignore the third dimension when doing the comparison. Now, we violate transitivity. Consider this example:

Listing 21: Second (incorrect) pass at an equals() method.

    //-- violates transitivity
    public boolean equals(Object o) {
        if (!(o instanceof Point2D)) {
            return false;
        }
        //-- if o is a Point2D, do an ignore-z comparison
        if (!(o instanceof Point2D)) {
            return o.equals(this);
        }
        //-- o must be a 3D point
        Point3D p3 = (Point3D) o;
        return super.equals(o) && p3.z == z;
    }

This version fixes the symetry problem, but introduces a transitivity problem. So, if you have these 3 objects:

  
  Point3D p1 = new Point3D(2, 3, 4);
  Point2D p2 = new Point2D(2, 3);
  Point3D p3 = new Point3D(2, 3, 12);
 

In this case, p1.equals(p2) and p2.equals(p3) both return true. However, p1.equals(p3) returns false. This is an indicator that the equals method is not transitive.

Unfortunately, there is no simple solution to this problem. This is a general problem in all Object-oriented languages, not just Java. The easiest way to fix this is to use composition instead of inheritance. In fact, that is exactly what the JDK does in several cases. For example, the TimeStamp class is a Date class with an extra field.

Here is a version using composition that avoids the problems of symetry and transitivity of the previous examples.

Listing 22: 3D Point build with composition instead of inheritance

public class Point3DComp {
    private Point2D point;
    private int z;
    public Point3DComp(int x, int y, int z) {
        point = new Point2D(x, y);
        this.z = z;
    }
    public Point2D asPoint2D() {
        return point;
    }
    public boolean equals(Object o) {
        if (!(o instanceof Point3DComp)) {
            return false;
        }
        Point3DComp p = (Point3DComp) o;
        return p.point.equals(point) && p.z == z;
    }
}
Consistent

This requirement states that if two objects are equal, they must remain equal unless (and until) one of them is modified. This is really little more than a reminder that mutable object’s equally can change over time as the contents of the object changes. This, of course, doesn’t apply to immutable objects. Generally, you should consider making objects immutable whenever you can because it simplifies the equality requirements.

Non-null Reference value

This requirement says that any object must not be equal to null. This is the reason that all equals() methods should begin with an instanceof check to make sure that the passed object is the of the correct lineage. You do not have to explicitly check to see if the argument is null — the instanceof operator always returns false if the first argument is null.

Building the Perfect equals()

Given the above requirements, here is a heuristic for building the perfect equals() method every time.

  1. Use == to check to see if you have been passed a direct reference to yourself.
  2. Use the instanceof operator to check the lineage of the object.
  3. Cast the object to the correct type.
  4. Check the equality of each field of the class. If any test fails, return false. Note that this will turn around and call the equals() method of the non-primitive fields of you class, so this can be time consuming. This should be done last after all the other (faster) tests have been passed.
  5. Make sure that your equals is symmetric, transitive, and consistent.
hashCode()

Like the equals() method, there are also very specific rules as to how to create a correct hashCode() method. In fact, any time that you override Object.equals(), you should override Object.hashCode() as well. The rules laid out by the J2SE specification are as follows:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

The second condition is the one of most importance because it dictates how many of the collection classes define equality. Here is an example. First, let’s look at an example of what happens if you neglect creating a hashCode() method. Consider the Point2D class from above, which doesn’t have a hashCode() method. If you tried to key a collection item from this class, it would fail.

Listing 23: Trying to key a collection item with an invalid hashCode

public class TestHash {
    public TestHash() {
         HashMap map = new HashMap();
         map.put(new Point2D(12, 12), "my point");
         System.out.println("Here is the point:");
         System.out.println(map.get(new Point2D(12, 12)));
    }
    public static void main(String[] args) {
        new TestHash();
    }
}

When you run this application, it prints "null" instead of "my point". Why? Because the default hashCode() method (from Object) doesn’t correctly calculate the hashCode. All the keyed collections in Java use the hashCode to place items in the appropriate slot. If two objects that should be identical don’t generate the same hashCode(), they cannot be retrieved from the collection.

Here is a version of Point2D that does correctly override hashCode().

Listing 24: A version of Point2D that correctly implements the hashCode() method

public class Point2DHash {
    private int x;
    private int y;
    public Point2DHash(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public boolean equals(Object o) {
        if (!(o instanceof Point2DHash)) {
            return false;
        }
        Point2DHash p = (Point2DHash) o;
        return p.x == x && p.y == y;
    }
    public int hashCode() {
        int result = 7;
        result = 3 * result + x;
        result = 3 * result + y;
        return result;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

Here is a reusable heuristic that allows you to correctly implement hashCode() for any class:

  1. Store a constant (prime) number in a variable (called result in the example above).
  2. For each field in the class that contributes to equals(), calculate a value for the field and add it to the result multiplied by a nontrivial prime number (3 in the above example)
  3. Return the result

Note that for arrays, you should iterate through the entire array to contribute to the result. You must resist the temptation of skipping fields to speed up the result because it will compromise your hashcode.

Antipatterns

Antipatterns are a response to the Design Patterns movement. If you can catalog a list of best practices and common design solutions, you can also catalog a list of worst practices and common but bad designs. Just like any architecture, J2EE won’t prevent you from doing something stupid, and in fact provides you with even more opportunities for stupid mistakes! To that end, this session presents a couple of very common worst practices that should be avoided like the plague.

"Uber Servlet" Antipattern

The first of the antipatterns is the "Uber Servlet" (also known as the "Fat Controller") pattern. This is an example of good intentions gone awry. The cause of this problem is the naive application of the Model-View-Controller design pattern discussed above. It is certainly a good thing to use the Model2 design pattern for web development (as embodied in Struts). However, if you try to use a single controller for everything, that single controller class becomes overly large, hard to debug, and starts growing all sorts of undesirable code to handle unusual circumstances. Even if you use a single controller for your MVC site, there is no rule that says that you can’t have any other servlets.

We had a client who was using this approach to manage every aspect of the application, using parameters passed to the controller to indicate what should happen. Because it was used for both normal processing and logon, the developers eventually created highly complicated logic that created a user session, immediately invalidated it, then re-created another one (there was some logic for doing this which escaped me then and now). Before they had finished, there were hundreds of lines of code (in a servlet that was already close to 5000 lines long) just to handle logging in. By changing logon to its own servlet, the entire application was simplified. The moral: don’t think that you can only have one master servlet. You can have as many as you need!

Notice that, even though Struts has a single controller, it’s controller does only one thing — map requests to actions, with its attendant form operations. If you use Struts, nothing says that you can’t create your own servlets to handle other jobs. In fact, it is probably a good thing that Struts handles this job for you and no others, because it encourages you to write other code to handle other stuff.

Finders that Return Large ResultSets

Another common misuse of the J2EE architecture has developers returning large result sets from entity bean finder methods. Especially if you just want a result set for display purposes, you should not use entity beans. When you create an entity bean, the application server must allocate resources for the beans. Thus, creating large numbers of beans generates a huge resource drain on the application server. Entity beans should only be used when you plan to update data, not display it.

If you need a large resultset to display some information, you should use a stateless session bean that connects directly to the database. These beans eat up far fewer resources than entity beans and will return the results much more quickly. In fact, if you need to update a large number of entities, you can write a stateless session bean that handles that directly with the database as well. Entities are designed for just that — small numbers of unique entities rather than large collections

Listing 25: Session bean that returns a list of Customer names

public class CustomerBean implements SessionBean {
    private SessionContext sessionContext;
    private java.util.List customerList;
    public void ejbCreate() {
    }
    public void ejbRemove() {
    }
    public void ejbActivate() {
    }
    public void ejbPassivate() {
    }
    public void setSessionContext(SessionContext sessionContext) {
        this.sessionContext = sessionContext;
    }
    public List getCustomerNameList() throws EJBException {
        Connection c = null;
        Statement s = null;
        ResultSet rs = null;
        try {
            c = getConnection();
            s = c.createStatement();
            RS = s.executeQuery("SELECT * FROM CUSTOMER");
            customerList = new Vector(20);
            while (rs.next())  {
                v.add(rs.getString("name"));
            }
        } catch (SQLException sqlx) {
            throw new EJBException(sqlx);
        }
        return customerList;
    }
    private Connection getConnection() throws SQLException {
        try {
            Context jndiContext = new InitalContext();
            DataSource ds = (DataSource) jndiContext.lookup(
                    "java:comp/env/jdbc/OrderEntryDS");
            return Ds;
        } catch (NamingException nx) {
            throw new EJBException(nx);
        }
    }
}

Summary

This session demonstrated a collection of J2EE best practices from a practical point of view. We looked at Web and EJB best practices and some J2EE Anti-patterns. If you would like to download the example from this presentation, go to http://www.thedswgroup.com/HTML/conferences.html.

For More Information


Some of the material presented here is adapted from my book Art of Java Web Development. It is guide to the topics required for state of the art web development. This book covers wide-ranging topics, including a variety of web development frameworks and best practices. Beginning with coverage of the history of the architecture of web applications, highlighting the uses of the standard web API to create applications with increasingly sophisticated architectures, developers are led through a discussion on the development of industry accepted best practices for architecture.

Described is the history and evolution towards this architecture and the reasons that it is superior to previous efforts. Also provided is an overview of the most popular web application frameworks, covering their architecture and use. Numerous frameworks exist, but trying to evaluate them is difficult because their documentation stresses their advantages but hides their deficiencies. Here, the same application is built in six different frameworks, providing a way to perform an informed comparison. Also provided is an evaluation of the pros and cons of each framework to assist in making a decision or evaluating a framework on your own. Finally, best practices are covered, including sophisticated user interface techniques, intelligent caching and resource management, performance tuning, debugging, testing, and Web services.

J2EE Strategies Part III

Input Validation

This is Part III in a IV part series on J2EE Design.

Input validation is always required even in simple web applications. The question is where do you do it: client or server-side? Each has advantages. Client side validation is nice because it provides instant feedback for the user. However, the downside to client validation is that it must be written in a scripting language, typically Javascript. Scripting languages are good for very small scripts (hence the name), but don’t scale well to serious development. They don’t have good variable scoping, strong types, or a sufficient object model.

Server-side validation allows you to use the full facilities of the Java language, which is of course quite robust. However, to do server-side validation requires a round trip to the server, meaning that you lose the nice instant gratification of client-side validation. Which should you use?

Client-side Validation

Because client-side validation must rely on scripting languages (whose short comings are listed above), it should always be thought of a part of the view of the application, not the model. In other words, you should never embed any business logic in JavaScript. It is fine for simple validations like "Must be all characters" or "Must be in phone number format". However, it should never be used for logic such as "No customer can have a credit limit over $1000". This is a business rule because it has more to do with why you are writing the application than how you are writing it. These business rules are prone to change and therefore should be consolidated in model classes. They should never be scattered throughout the presentation layer of your application in Javascript!

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>
<HEAD>
<TITLE>
ScheduleEntryView
</TITLE>
</HEAD>
<BODY>
<H1>
Add Schedule Item
</H1>
<hr>
<html:errors/>
<html:form action="add.do">
<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) {
        ae.add("duration", new ActionError(
           "error.invalid.duration", "8"));
    }
    if (text == null || text.length() < 1) {
        ae.add("event text",
            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.