Building simple generators
4.5 T HE TIER GENERATOR MODEL
A tier generator builds all of the code for one tier or section of an application. The most common example is the constructor of a database access layer tier of a web or client/
server application. In this section, we show several forms of a very basic tier generator.
You can use the code here as the basis for your tier generator.
Build Base Class Test Code
Design Generator
Develop Templates From Test Code Develop Input Parser
Develop Output Code Builder Build Derived Class
Test Code
Figure 4.19
A set of design and implementation steps for building a partial-class generator
THETIERGENERATORMODEL 91 4.5.1 Uses and examples
Besides building database access layers, there are a number of possible uses for a tier generator. These include creating:
• The RPC layer of an application that exports a web services interface
• The stub code in a variety of different languages for your RPC layer
• The dialog boxes for a desktop application.
• The stored procedure layer for managing access to your database schema
• Data export, import, or conversion layers
The input to a tier generator is a definition file from which it gathers all of the informa-tion required to build the complete code for the tier. The basic I/O flow is shown in figure 4.20.
The generator takes a definition file, which contains enough information to build all of the classes and functions of the tier. It then uses this information in conjunction with a reservoir of templates to build the output source code. This output code is pro-duction ready and waiting for integration into the application.
Our first example of tier generator builds structure classes from XML. It is very closely related to the partial-class generator example. The only difference is the name of the classes that it generates and the format of the definition file. At the implemen-tation level, the two types of generators are very similar—it’s in the roles of the two types of generators that there is a larger divergence.
The role of the tier generator is to take responsibility for all of the code in the tier.
The partial-class generator model opts instead to take partial responsibility for the tier and then lets the engineer create the rest of the derived classes that will complete the functionality for the tier.
This structure generator uses XML to specify the classes and their fields, as opposed to the simple text file in the partial-class generator version. The XML version of the same file used in the original generator is shown here:
Definition File
Tier Generator Output Source Code
Compiler
Executable
Templates
Figure 4.20
The input and output flow for a tier generator
<classes>
Note that although this XML file is much bigger, it has the ability to expand to handle extra information more easily than a simple text file. For example, you could add types to each field by specifying a type attribute on the field tag. To do the same on the text file would require creating an increasingly complex syntax. XML also has the advantage of having editing and validation tools that come in handy as your XML files grows larger.
Listing 4.15 contains the code that implements the XML version of the structure class tier generator.
require 'rexml/document' require "erb/erb"
doc = REXML::Document.new( File.open( "fields.xml" ) )
doc.root.each_element( "class" ) { |class_obj| erb = ERb.new( File.open( "field_class.template.java" ).read ) new_code = erb.result( binding ) print "Creating #{class_name}.java\n"
File.open( "#{class_name}.java", "w" ).write( new_code ) }
q
The each_element iterator finds all of the elements matching the specified name and passes it into the code block. Here you use the each_element iterator to get all of the class elements in the XML file.w
Next, use the attributes method to get an array of the attributes on the class ele-ment and dereference the array to get the name attribute.e
This code uses the same each_element iterator to get the fields from the class ele-ment. Inside the code block, you push the field name into the array of fields. Use the text method to get the text of the element and the strip method to remove any leading or trailing white space.Listing 4.15 The tier generator: building structure classes from XML
Gets the class name
THETIERGENERATORMODEL 93
r
This code creates the ERb template object from the text template. It then runs the tem-plate using the result method and passes the variables in the current scope into the template with the binding method.Listing 4.16 shows the template used by the tier generator to build the data structure classes.
public class <%= class_name %> {
<% fields.each { |field| %>
protected String _<%= field %>;<% } %>
public <%= class_name %>() { <% fields.each { |field| %>
_<%= field %> = new String();<% } %>
}
<% fields.each { |field| %>
public String get<%= field.capitalize %>() { return _<%= field %>; } public void set<%= field.capitalize %>( String value ) { _<%= field %> = value; }
<% } %>
}
4.5.2 Developing the generator
Developing a tier generator is much like building any of the other generators in this chapter. We show the steps in figure 4.21, but you should follow your own path; these steps are merely a starting point.
Let’s examine these steps in detail:
• Build the test code—One of the great things about building a code generator is that you start at the end. The first step is to prototype what you would like to generate by building the output code by hand. In most cases you already have the code you want to generate in hand because it’s already part of the application.
Listing 4.16 field_class.template.java
Build Test Code
Design Generator
Develop Templates From Test Code
Develop Input Parser
Develop Output Code Builder
Figure 4.21
The design and implementation steps for developing a tier generator
• Design the generator—Once you have the output, you need to determine how you are going to build a generator that will create the test code as output. The most important job is to specify the data requirements. What is the smallest possible collection of knowledge that you need to build the output class? Once you have the data requirements, you will want to design the input definition file format.
• Develop the input parser—The first implementation step is to build the definition file parser. In the case of XML, this means writing the Rexml access code to read in the XML and to store it in some internal structures that are easy for the tem-plates to handle.
• Develop the templates from the test code—Once the input is coming into the gener-ator, you must create the templates that will build the output files. The easiest way to do this is to take the test code you started as the starting point for the template.
• Develop the output code builder—The final step is to write the glue code that runs the templates on the input specification from the definition file and builds the output files. At the end of the development, you should be able to run the gener-ator on your definition file and have the output match the test code that you cre-ated in the beginning of the process.