This tutorial shows you how to create simple data container objects using the Basic Data Container template set. You should download this template set before starting this tutorial.

1. Purpose

The Basic Data Container template set allows you to create simple data container objects using a small text file. The data container objects are very simple Java classes which contain nothing more than get and set methods and corresponding member variables. Here is an example:
public class Person {

  private String     iFirstName;  
  private String     iSecondName;
  private int        iSalary;
  
  public void setFirstName( String rFirstName ) {
    iFirstName = rFirstName;
  }  

  public String getFirstName() {
    return iFirstName;
  }  
  
  public void setSecondName( String rSecondName ) {
    iSecondName = rSecondName;
  }  

  public String getSecondName() {
    return iSecondName;
  }  
  
  public void setSalary( int rSalary ) {
    iSalary = rSalary;
  }  

  public int getSalary() {
    return iSalary;
  }  

}

This type of very simple class can then be used as a way of passing information in your application. This can be useful for distributed computing applications using RMI or CORBA. Or it can form the basis of an object-relational mapping. We will take for granted that some part of your software design calls for simple objects of this type that are then either extended by more complex classes or delegated to as a data store. In essence these types of classes are the Java version of C/C++ structs.

2. Describing Basic Data Containers

The philosophy behind code generation is: Don't Repeat Yourself. This is a very commmon strategy in software design. Following this principle we ask; what are the essential characteristics of these simple data objects?

First, they have a name. That is each simple data object has a class name which identifies it and is also used as the name of the Java source code file. In the example above this name is Person.

Second, they have a list of data fields. In the example above these are FirstName, SecondName, and Salary. And each of these fields has a type: String, String, and int. So we can see that the fields form of list of pairs: field name and field type for each field.

Let's keep things easy. For this tutorial we'll stick to the idea that a basic data container object is fully described by its name and list of fields. When you are more experienced with Jostraca you will find it easy to add more meta data to the description. For now, we'll stick with this simple set of meta data. The next question is; how do we represent this data. Well we could use XML. In fact, XML is a very good idea and is probably the best way to represent meta data for any serious application.

However we are trying to be simple here, so we will define a very simple text file format. You should note that this does not stop us from using XML in future if we decide we need to. We can simply use Jostraca to translate our text file into an XML file and then use that. This maintains a single source for the meta data. So using a text file format is not really a dead end and sometimes simplicity has its own value.

Ok, so here's the format:
Person
  FirstName  String     
  SecondName String     
  Salary     int
;
As you can see, it is very simple. All whitespace is ignored and the basic syntax is: first comes the name of the data container, followed by the list of fields. Each field is simply described by two words, the first is the name of the field, the second is the data type of the field. Finally the description ends with a ;

It is easy to dream up simple text file formats. The real work is parsing them, which is why XML is the best approch most of the time. However, because this type of meta data is so common, Jostraca provides some utility classes for parsing it. This should make your life easier in common situations like this.

The general question; how do I get hold of my meta data? is one which has many answers. If you are building a large scale appllication it is probably better to write some form of XML wrapper instead of dealing with XML data directly. In smaller work, it might be quicker to just traverse the XML manually or write a quick text file parser. Even a Java properties file can be used. Finally you might choose to hard code the meta data directly into the template, although this should be avoided.

At a more advanced level, and especially when dealing with legacy systems you can use other tools to parse SQL or existing source code and extract meta data from that.

You should not be concerned about writing small pieces of code to help handle meta data. The content of meta data may change from project to project, but the form will remain pretty much the same. Basic Data Containers are useful in many different systems. This justifies a special text file format and a set of utility classes for this common special case.

3. Setting Up the Template

So what sort of template will we use to construct the Person class above? This is a question you will often face when using Jostraca. We recommend a practical approach; first develop the end result. Write an example of the type of code you want to produce automatically. This gives you a clear goal to aim for. It also allows you to concentrate on the programming logic of the code. You can think about Jostraca later.

Next, think about the meta data. How do you want to represent it? A simple text file, XML, or something more complex? How do want to access it? Using utility classes can help. Or you can access it directly. Once you have made these decisions and created some test meta data, you can create the Jostraca template.

Taking the example of the code you want generated, convert it into a Jostraca template. Copy the file and give it a name like: DataContainer_java.jtm. This name tells you several things. First, the .jtm extension tells you that it is a Jostraca template. Second, the name DataContainer tells you what type of code it produces. Third, the suffix _java tells you that the template script language is Java. That is, the language that you use to provide the code building instructions is Java. You also happen to be producing code in Java, but this is the target language, and might as well be random text as far as Jostraca is concerned.

Next, open up the new template in a text editor and add the Jostraca bits. Insert a conf section. The minimal conf section is:
< @conf
main.JostracaVersion = 0.1
>
This indicates what version of Jostraca this template expects. This allows for easy backwards compatibility, so it is a required setting. You can also add other settings to the conf section. Refer to the reference pages for more information.

Now you need to load all that meta data. Since Jostraca is meant to be actually useful, let's assume that we want to generate more than one basic data container class. Our syntax for the text file allows us to separate each data container description with a ; so that we can place more than one in a single text file.

To use the meta data we need to import the Jostraca utility classes that can read this meta data. These classes are not imported into our basic data container object. Rather they are used by the JostracaCodeWriter java program which will write the data container source code. So we need to tell Jostraca to import them into the JostracaCodeWriter. We do this with a special import section:
<% @import
import org.jostraca.resource.SimpleDataObject;
import org.jostraca.resource.SimpleDataObjectReader;
%>
SimpleDataObject represents the meta data for one basic data container objects (name and fields) and SimpleDataObjectReader parses the text file. These utility classes have been given fairly generic names because they will be used in many different contexts.

Next we need to set up the meta data so that we can access it in our template code. Initialisation of meta data is usually done in the init section. This section is executed once before any source code is written. The init section also provides a place to tell Jostraca what files to produce. These instructions are given using special template service methods. These are basically methods calls in the JostracaCodeWriter which control the code generation process. They all begin with an underscore so that they are easily identifiable. Here is the initialisation section:

<% @init
String schemaFile  = _getFirstUserArg();
if( 0 == schemaFile.length() ) {
  System.err.println( 
    "Schema file not specified. Use -a schemafile.txt." 
  );
  System.exit(1);
}
SimpleDataObject[] objects     = SimpleDataObjectReader.read( schemaFile );
int                numObjects  = objects.length;
String[]           objectNames = new String[ numObjects ];
for(int objectI = 0; objectI < numObjects; objectI++) {
  objectNames[ objectI ] = objects[ objectI ].getName();
}
_setFileNameRoots( objectNames );
%>

What does all this do? We'll explain it step by step.

String             schemaFile  = _getFirstUserArg();
if( 0 == schemaFile.length() ) {
  System.err.println( "Schema file not specified. Use -a schemafile.txt.");
  System.exit(1);
}
This gets the first command line argument entered by the user using the -a option to Jostraca. This makes the template versatile - the user specifies the meta data text file (the schema) to use. This facility is provided so that different meta data can be used with the same template. The name of the text file could have been hard coded like this:
String             schemaFile  = "myschema.txt";
We also provide a short error message if the schema file is not specified.

SimpleDataObject[] objects     = SimpleDataObjectReader.read( schemaFile );
The SimpleDataObjectReader API is very simple. It has only one purpose; to parse a text file and find SimpleDataObjects. It returns these in an array.

int                numObjects  = objects.length;
String[]           objectNames = new String[ numObjects ];
for(int objectI = 0; objectI < numObjects; objectI++) {
  objectNames[ objectI ] = objects[ objectI ].getName();
}
_setFileNameRoots( objectNames );
This piece of code just creates a String array of the names of the SimpleDataObjects. We do this so that we can pass this String array to the template service method _setFileNameRoots. This specifies the names of the files that we want to create. The suffix .java will be automatically added to these names as a default option. We could specify the suffix explicitly by saying:
_setFileNameSuffix(".java");
For example, if we were generating Perl source code we would have to say:
_setFileNameSuffix(".pl");

At this point we have now told Jostraca what we want to do: create a set of files from this template and name them after the basic data container names. The next thing to do is tell Jostraca what we want to put in the template.

4. Writing the Template

Jostraca loops through each file that we specified in _setFileNameRoots. For each file, we want to get the meta data for that data container object. This means that we want an index into the objects array . This is very easy to do:
<%
SimpleDataObject object = objects[ _getFileIndex() ];
%>
Notice that this code in not in any section. In fact, it is in the default section which means that it is executed in place for each file to be generated. The template service method _getFileIndex returns the index of the current file so we can use this as an index into the objects array.

Since we already have an example of what we want to produce in the template, we simply work through the source code, replacing specific names with Jostraca template code. Thus, for example:
public class Person {
is replaced with
public class <%=_getFileNameRoot()%> {
The template service method _getFileNameRoot returns the file name root of the current file being generated. Notice that we use the special abbreviation <%=...%> to insert the value into the source file being generated. We could also use <% _insert(...); %> for the same effect.

A basic data container object consists of a name and a list of fields. The SimpleDataObject utility class provides a way to loop through the fields and easily extract the name and type of each field. Thus
  private String     iFirstName;  
  private String     iSecondName;
  private int        iSalary;
is replaced with
  <% while( object.nextField() ) { %>
  private <%=object.getFieldType()%>     i<%=object.getFieldName()%>;
  <% } %>
What does this do? The object.nextField method advances to the next field in the list of fields describing the data container. It starts just before the first field, so you need to call it first before accessing field data. This convention allows us to write simple while loops such as the one above to access the field data. The object.nextField method returns false when there are no more fields left.

The object.getFieldName and object.getFieldType methods return the String values of the name and type of the current field. In our example these are, for each item in the loop: FirstName and String, SecondName and String and finally Salary and int. These Strings are inserted into the source code. Notice that we use a naming convention to indicate that we are creating instance variables - we prefix each field name with an i. This is simply one coding convention. You don't have to use it. You can use any coding convention you like. However some may require more String manipulation than others. We have opted for a simple solution in this case.

Once we have created the instance variables we need to create the get and set methods. We do this using:
  <% while( object.nextField() ) { %>
  public void set<%=object.getFieldName()%>( <%=object.getFieldType()%> 
                                                   r<%=object.getFieldName()%> ) 
  {
    i<%=object.getFieldName()%> = r<%=object.getFieldName()%>;
  }  

  public <%=object.getFieldType()%> get<%=object.getFieldName()%>() {
    return i<%=object.getFieldName()%>;
  }  
  <% } %>
You'll notice that we did not need to reset the nextField method. It automatically resets itself.

In the above piece of template code you can see how Jostraca inserts the field names and values in the appropriate places. Once again we use a coding convention to make life easier: r is prefixed to formal parameters. And once again, this is only a coding convention - you can change it if you don't like it.

Placing all these pieces together, here is the final template. You should compare it to the original Person class.

<% @conf
main.JostracaVersion = 0.1
%>

<% @import
import org.jostraca.resource.SimpleDataObject;
import org.jostraca.resource.SimpleDataObjectReader;
%>

<% @init
String             schemaFile  = _getFirstUserArg();
if( 0 == schemaFile.length() ) {
  System.err.println( "Schema file not specified. Use -a schemafile.txt.");
  System.exit(1);
}
SimpleDataObject[] objects     = SimpleDataObjectReader.read( schemaFile );
int                numObjects  = objects.length;
String[]           objectNames = new String[ numObjects ];
for(int objectI = 0; objectI < numObjects; objectI++) {
  objectNames[ objectI ] = objects[ objectI ].getName();
}
_setFileNameRoots( objectNames );
%>

<%
SimpleDataObject object = objects[ _getFileIndex() ];
%>

public class <%=_getFileNameRoot()%> {

  <% while( object.nextField() ) { %>
  private <%=object.getFieldType()%> i<%=object.getFieldName()%>;
  <% } %>

  <% while( object.nextField() ) { %>
  public void set<%=object.getFieldName()%>( <%=object.getFieldType()%> 
                                                   r<%=object.getFieldName()%> ) 
  {
    i<%=object.getFieldName()%> = r<%=object.getFieldName()%>;
  }  

  public <%=object.getFieldType()%> get<%=object.getFieldName()%>() {
    return i<%=object.getFieldName()%>;
  }  
  <% } %>

}

5. Generating the Data Containers

This is the easy bit - all of the hard work has been done. All we need to do now is execute Jostraca. At this point you should download the Basic Data Container template set if you have not done so already. You will find instructions for using this template set included in the download. Go into the folder where you unpacked the template set files. At the shell or command prompt, enter: jostraca DataContainer_java.jtm -a "sampleschema.txt". This will create two files: Person.java and Company.java. Review these files and take a look at sampleschema.txt to see how they fit together. Finally review DataContainer_java.jtm which is the file we created above.

Jostraca will also create a .jostraca backup folder. This folder is used to store previous versions of the generated files. This safety mechanism can be turned off by using the -B option.

To use the data containers, you will need to compile them manually. Jostraca simply generates code - what you do with it is up to you. To integrate the generated data containers into a real world project you will need to specify the appropriate Java package for the data container classes and probably some import statements for them as well. The template set instructions will tell you how to do this.

This is now the point at which Jostraca becomes really useful. By making a simple change to your text file you can regenerate the data containers. for example you could extend:
Person
  FirstName  String     
  SecondName String     
  Salary     int
;
to
Person
  FirstName  String     
  SecondName String     
  Salary     int
  Title      String
;
Now regenerate. All of your code is automatically updated.

Perhaps you may still be wondering if this really is useful - after all these are only simple classes - they can easily be updated by hand. However you should consider the context in which they will be used. In a real world application Jostraca can be used to create not only the data containers, but also the SQL tables, the stored procedures, the database wrappers, the modal dialogue windows, the business reports, the JSP pages, the Enterprise Java Beans, the IDL interfaces, the configuration files, the XML data files and the many other source files which all depend in one way or another on the simple list of object names and fields.

In this case, regeneration rebuilds your entire application. All you have to do is edit a simple text file. And you know it's correct. There is no possibility of human error. Jostraca won't forget to update a critical stored procedure.

6. The Development Cycle

The development cycle for Jostraca is split into two main phases: developing the template and modifying the template and meta data.

The development phase takes the most work. In this phase you create an example of what you want to produce and then you turn that example into a working template.

In the second phase you make minor modifications to the template and update the meta data as necessary. During this phase you use Jostraca to rebuild your application as needed, thereby maintaining consistency and reliability.

Since Jostraca is a command line application you can easily integrate it into your build cycle using make or similar tools. This ensures that templates will be rebuilt when necessary.

6. The Design Philosophy

Finally we will touch briefly on the design philosophy of Jostraca. You may have had some slight misgivings about the code we were producing. After all, the field names and types were hard coded into the source files. Isn't this a bad thing?

The answer is Yes! It is a bad thing. If you were to manually write the data container objects it would be a very bad thing. You'd have to manually change them each time the object descriptions changed.

But Jostraca allows you to do bad things. This is because it preserves the Don't repeat yourself principle. It doesn't matter how hard-coded your final source code is. You don't write the final source code. Jostraca does. You control the source code by providing a concise description of the system. There is no redundancy or lack of consistency because everything is controlled from one location - the meta data file.

7. Further Information

To find out more about Jostraca, work through the other tutorials and the examples - the best way to learn is by doing. If you really want to know the gory details, refer to the manual and the reference section.

If you had any problems with this tutorial please let us know: tutorials@jostraca.org.