182
CHAPTER 9
H
ANDLING
DATA
*/                                                                 
public Name get( int index )                                        
{
return (Name)_data.get( index );
}
/**                                                               
* Reads in the input stream                                      
*/
public void read()                                                
{
StringBuffer line = new StringBuffer(); 
line.setLength( 0 );
try {
while( true )
{
int nChar; 
if ( ( nChar = _in.read() ) == -1 )
break;
char cChar = (char)nChar;
if ( cChar == '\n' )
{
process_line( line );
line.setLength( 0 );
}
else
{
line.append( cChar ); 
}
}
}
catch( IOException except )
{
if ( line.length() > 0 )
process_line( line );
}
}
/**
* Processes a single input line.
*
* @arg line The row text
*/
protected void process_line( StringBuffer line )
{
ArrayList fields = new ArrayList();
boolean inQuotes = false;
boolean escaped = false;
StringBuffer text = new StringBuffer();
The data 
accessor
e
Input parsing 
system
r
Pdf file size limit - Compress reduce PDF size in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
C# Code & .NET API to Compress & Decompress PDF Document
pdf change font size in textbox; acrobat compress pdf
Pdf file size limit - VB.NET PDF File Compress Library: Compress reduce PDF size in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
VB.NET PDF Document Compression and Decompression Control SDK
pdf compression settings; apple compress pdf
CASE
STUDY
A
SIMPLE
CSV-
READING
EXAMPLE
183
for( int index = 0; index < line.length(); index++ )
{
if ( escaped )
{
text.append( line.charAt( index ) ); 
}
else 
{
if ( line.charAt( index ) == '\"' )
{
inQuotes = inQuotes ? false : true; 
}
else if ( line.charAt( index ) == '\\' )
escaped = true;
}
else if ( line.charAt( index ) == ',' && ! inQuotes )
{
fields.add( new String( text ) );
text.setLength( 0 );
}
else 
text.append( line.charAt( index ) );
}
}
}
if ( text.length() > 0 )
fields.add( new String( text ) );
String strArray [] = new String[ fields.size() ];
fields.toArray( strArray );
process_fields( strArray );
}
/**
* This is the main processor for a single row of string fields 
*
* @arg fields The array of strings that make up the row.
*/
protected void process_fields( String fields[] )
{
Name data = newRecord(); 
data.first_name = process_first_name( fields[ 0 ] );
data.middle_initial = process_middle_initial( fields[ 1 ] );
data.last_name = process_last_name( fields[ 2 ] );
data.age = process_age( fields[ 3 ] );
addRecord( data );
}
/**
VB.NET PDF File Split Library: Split, seperate PDF into multiple
Program.RootPath + "\\" 1.pdf" ' set split option Dim options As SplitOptions = New SplitOptions(SplitMode.BySize) ' limit the size of each file to 0.1M
best pdf compression tool; can a pdf be compressed
C# PDF File Split Library: Split, seperate PDF into multiple files
Program.RootPath + "\\" 1.pdf"; //set split option. SplitOptions options = new SplitOptions(SplitMode.BySize); //limit the size of each file to 0.03M
pdf compress; reduce pdf file size
184
CHAPTER 9
H
ANDLING
DATA
* Creates a new record
*/
protected Name newRecord( ) { return new Name(); }
/**                                                                 
* Processes the First Name                                         
                                                                 
* @arg first_name The First Name                                  
*/                                                                 
protected String process_first_name( String first_name ) {          
return first_name;                                                
}                                                                                            
/**                                                                 
* Processes the Middle Initial                                     
                                                                 
* @arg middle_initial The Middle Initial
*/ 
protected String process_middle_initial( String middle_initial ) {
return middle_initial;
}
/**
* Processes the Last Name
*
* @arg last_name The Last Name
*/
protected String process_last_name( String last_name ) {
return last_name;
}
/**
* Processes the Age
*
* @arg age The Age  
*/
protected Integer process_age( String age ) {
return Integer.getInteger( age );
}
/**
* Adds a record to the data collection
*
* @arg data The new record
*/
protected void addRecord( Name data ) { _data.add( data ); }
}
q
The Name class stores the data for each name in the CSV file.
w
The NameReader constructor takes an InputStream, from which it will read the
CSV stream.
e
The get method returns the Name object at the specified index.
Handlers 
for each 
field
t
C# PowerPoint: How to Set PowerPoint Rendering Parameters in C#
2007 or above) slide into PDF document or Bitmap Object due to memory limit and performance REImage CropImage(Rectangle sourceRegion, Size targetSize); Bitmap
adjusting page size in pdf; advanced pdf compressor online
C# Excel: Customize Excel Conversion by Setting Rendering Options
int)(originalWidth), (int)(originalHeight / 2)), new Size((int)(originalWidth created image object/collection to these file formats, like PDF, TIFF, SVG
change font size pdf form reader; best way to compress pdf files
CASE
STUDY
A
SIMPLE
CSV-
READING
EXAMPLE
185
r
The read method processes the data from the InputStream and stores it in the
_data array.
t
Each field has a process method, which you can override in a derived class to create
any custom processing you may require.
The MyReader class derives from NameReader and could implement special proc-
essing for any of the fields. This example does not, however, make any changes to the
field processing behaviors:
import java.io.*;                                                                    
import NameReader;                                                                       
class MyReader extends NameReader
{
public MyReader( FileInputStream in )
{
super( in );
}
Here’s the test code to use MyReader to read the 
Name
entities from the file:
import java.io.*;
import MyReader;
public class test {
static public void main( String args[] )
{
FileInputStream in;                                           
MyReader reader;                                              
try
{
in = new FileInputStream( "data.csv" );                     
reader = new MyReader( in );                                
reader.read();                                              
in.close();                                                 
for( int index = 0; index < reader.size(); index++ )        
                                                          
System.out.println( reader.get( index ).first_name );     
                                                          
} catch( Exception except ) {
}
}
}
Shows the file object
Prints the 
first_name 
field of each 
record
Shows the CSV reader
Opens the file
Closes the file
Creates the CSV reader 
and reads the file
VB.NET Excel: VB Methods to Set and Customize Excel Rendering
on the fixed image size ration that the size is limited users to convert and save Excel file into multiple Excel to other document files, like PDF with online
adjust size of pdf file; adjust size of pdf
186
CHAPTER 9
H
ANDLING
DATA
9.2.5
Performing system tests
You can test the generator by using the simple system test framework (described in
appendix B) to verify that the output of the generator is the same as the known goods
that you stored when you ran the test and found the output acceptable.
Here is the input definition file for the system test framework:
<ut kgdir="kg">
<test cmd="ruby -I../lp csvgen.rb examples/classes.xml" out="examples/
Reader.java" />
</ut>
In the next section, we look at a different kind of generator that builds code to translate
existing data into a predefined format for data import.
9.3
T
ECHNIQUE
DATA
ADAPTERS
Another common use for generation is to build adapters that read custom formats and
convert the data into a form required by the target system. This is a data adapter tech-
nique because the adapter takes the data from one source and, using a set of filters and
processing, adapts that data to a form suitable for a target system.
The ideal architecture has a data adapter framework into which each customized
data adapter fits. Each adapter is suited to a particular input format. The framework
defines the format that the adapter must match in order to bring data into the system.
Let’s take a look at the specific tasks we expect this generator to do. 
9.3.1
Roles of the generator
Start with a set of responsibilities for the generator:
• Build the data adapter that converts the input into the form required for insertion
into the database.
• Create code that embeds documentation that will be used later to generate tech-
nical documentation.
To clarify the role of the generator, you must also define what the generator will not do.
In this case, our generator will not be responsible for building design documentation
for the adapter or creating documentation about the input format.
With this information about the role and responsibilities of the generator clearly
understood, let’s examine the architecture of the generator.
9.3.2
Laying out the generator architecture
For the data adapter generator, we chose a tier-generation pattern because we want to
build entire data adapters from abstract models. The generator reads the description of
the data and builds the data adapter using a set of templates. You can write custom
code to add fields or alter the interpretation of fields from the incoming data. The flow
of input and output is shown in figure 9.2.
T
ECHNIQUE
BINARY
FILE
READER
/
WRITER
187
When you build this generator, you already know the data format requirements of the
target system. The only unknown is the incoming file format. This greatly simplifies
the design of the generator as compared to a generator where both the input and out-
put formats are unknown.
9.3.3
Processing flow 
This generator is very application specific. This means that customizing it for your sit-
uation may not be simple. The general processing steps are as follows:
Reads in and stores the data description.
Reads in the custom code and merges it into the data description.
Creates a buffer to hold the code for all of the fields.
Follows these steps for each field:
If the field is processed without customizations, uses the standard field 
template to build the field code.
If the field has customized processing, uses the custom field template and gives 
it the custom code and the field definition.
Uses the adapter template to build the adapter with the field code buffer.
Finally, let’s make one last data-handling generator; this one builds reader/writer code
for binary files.
9.4
T
ECHNIQUE
BINARY
FILE
READER
/
WRITER
Proprietary binary file formats are excellent for reading and writing efficiency, but they
lock customers into a file format that they cannot read without dedicated software.
Using a generator to build your binary file reader/writer code has these advantages:
• The file definition is abstracted so that anyone can write a program that can read
and parse the definition file.
Generator
Adapter
Template
Data
Description
Field
Template
DataAdapter
CustomCode
CustomField
Template
ConverterInfrastructure
InputData
DB
Figure 9.2
A generator that builds 
data adapters
Data adapter generator
188
CHAPTER 9
H
ANDLING
DATA
• The generator can build support for the file format in a variety of different languages.
• Documentation for the file format can be generated automatically.
• The generator can be reused to build support for any number of binary file formats.
Now let’s look at some of the specifications for this type of generator.
9.4.1
Roles of the generator
First, let’s specify what the generator will and will not do. Our generator will be respon-
sible for:
• Creating the read and write code for a given file format in one or more languages.
• Using the embedded documentation standard for the target language as you build
the code for the file format handler.
The generator will not be responsible for:
• Building unit test cases for the code.
• Building design documentation for the test cases.
• Building any application logic around the file-format handler.
• Validating the input file beyond basic format size and string validation.
• Performing cross-field validation of the input file as it is read.
With these responsibilities clearly defined, you can now specify the architecture of
the generator.
9.4.2
Laying out the generator architecture
The generator takes the binary file format as input and uses a set of templates—one or
more per language—to develop the output reader/writer code. Figure 9.3 shows the
tier-generator architecture for the binary file reader/writer generator.
9.4.3
Implementation recommendations
Here are some tips that should help you when developing this binary file reader/writer
generator:
Generator
CTemplates
BinaryFile
Format
Definition
CLibrary
CProgram
InputData
Python
Library
Python
Program
InputData
Python
Templates
Figure 9.3
A generator that can build 
binary file I/O code for multi-
ple output languages—
in this case, C and Python
S
UMMARY
189
• This generator should not allow for custom code. Leave all of the language-spe-
cific elements of the library implementation to the templates. This ensures porta-
bility between languages.
• The generator needs to ensure that all of the default values for the fields (e.g., the
type and the default value) are set within the generator itself before the templates
are invoked. If the generator handles the defaults, you will not have a problem with
the templates handling the interpretation of the default values in different ways.
• When you generate for multiple languages, you will have to create a set of con-
stant types for each of the machine types. The generator leaves the interpretation
of the machine types into language types up to the templates.
• Some languages (e.g., Java) have implicit big or little endian ordering to their
machine types. You need to account for this in the design of your file format.
Ruby and Perl allow for both endian styles when reading binary files.
9.4.4
Processing flow 
Here is the basic series of steps that you can use as a starting point for your generator:
Reads in the binary file format.
Normalizes all of the defaults so that the templates get fully defined structures for
every field.
Runs the template for each language and stores the result.
9.5
F
INDING
TOOLS
TO
DO
IT
FOR
YOU
The field of binary file format reader/writer generators was limited at the time of this
writing. The one we could find was Flavor, which builds C++ and Java file readers for
binary audio formats from an XML description (http://flavor.sourceforge.net). A handy
web site for finding the format of binary files is the Wotsit archive of file formats
(www.wotsit.org).
9.6
S
UMMARY
Handling file formats and data conversion presents an ideal opportunity to use code
generation, not only to develop the file support quickly but also to abstract the file for-
mat so that a number of different outputs can be created. This includes support for dif-
ferent languages, documentation, and test code.
This chapter has covered many of the key data-handling tasks with generation
approaches. These tasks included reading and writing text (CSV) files, reading and
writing binary files, and performing data-format conversion for input or export.
In the next chapter, we’ll look at generators that create database access layers. 
Binary file reader/writer generator
190
C
H
A
P
T E R
1 0
Creating database 
access generators
With contributions from Eric Rollins
10.1 Benefits of database access 
generators 191
10.2 The big picture e 192
10.3 Preparing for common concerns s 195
10.4 Workflow comparison n 198
10.5 A case study: EJB generation n 199
10.6 Technique: generating JDBC C 212
10.7 Technique: generating database 
access layers for ASP P 215
10.8 Technique: generating database 
access layers for ASP.NET T 218
10.9 Technique: Generating database 
access classes for Perl DBI I 220
10.10Technique: generating database 
access classes for PHP P 223
10.11Off-the-shelf: AndroMDA A 226
10.12Off-the-shelf: XDoclet t 227
10.13Design tips s 228
10.14Finding a tool to do it for you u 229
10.15Summary 229
I desperately needed a tool to make EJB development easier and less time consuming.
Ara Abrahamian (XDoclet team leader)
Teaching engineers how to use code generation for database work is my primary reason
for writing this book. This motivation comes from some personal experiences with
database work. 
My first experience with generating database access code was building stored pro-
cedures for an Oracle database. I was working with a partner, a database engineer who
had already built the stored procedures for inserting, updating, and deleting records
for the first three of the 70-plus tables required in the application. To help him, I tried
B
ENEFITS
OF
DATABASE
ACCESS
GENERATORS
191
a code generation approach. Two hours and 150 lines of Perl later, we were able to
generate about 90 percent of the stored procedures. The other 10 percent were written
by hand and wrapped the generated procedures in larger transactions.
Our generator had a simple design. The front end read the SQL generated by the
ERWin schema design tool and stored all of the tables and fields. The back end used
templates to build the insert, edit, and delete stored procedures from the table and
field data.
We estimated that the generator saved us about a month’s worth of tedious effort.
In addition, the code was nearly bug-free. At the time we shipped the application, only
two bugs had been logged against the stored procedures.
Later, we went on to use additional generators for the database layer. As a result
of this success, we also used generators on other portions of the project, such as the
user interface.
From that moment on, I was a true believer in code generation for database access,
and I remain so to this day. In this chapter, we look at the high-level benefits you’ll
reap by using database access generators. 
10.1
B
ENEFITS
OF
DATABASE
ACCESS
GENERATORS
Here are some of the reasons that code generation and database access are an ideal pairing:
• It doesn’t take a lot of effort to make a big impact on productivity in database work—
As I’ve discovered firsthand, in two hours it’s possible to build a generator that
can save you weeks of effort. 
• It is important to keep the design of the database abstracted from the code that imple-
ments that design—Code generation can help achieve that goal by moving the
schema into an abstract definition. In our example in the introduction, we main-
tained the design of the database schema in ERWin and used the output from
ERWin as a data source when constructing our stored procedures. Later we added
more generators that built the application code that sat on top of the tables and
stored procedures. The ERWin model acted as our abstracted form of the database. 
• Database code is uniquely repetitive—This makes database code an ideal target
for generation.
• The database is at the core of the system—When you have generated the database
and the surrounding access code, they will have a consistent design and interface.
This means that it becomes easy to generate the layers that sit on top of the
database. If the database is hand-coded, then the layers above it will need table-
specific code to handle the design of a particular table or group of tables.
• The complete system is often spread across several systems and languages—In our
example, the stored procedure layer was the second of three database access
components required for the production system. The first was the database
physical schema, written in Oracle SQL. The stored procedure layer itself was
Documents you may be interested
Documents you may be interested