BPP in Web Applications using SQL

by Karl Castleton (2-13-2004)

It is common for software engineers (programmers) to be enthusiastic about solving a problem that they have not in the past. They show a diminished zeal for a similar solution when they see the problem a second time, and still less when it is seen a third time. This leads to them attempting to reuse the same solution or attempting to generalize it which makes the second solution “larger” than it needs to be. An alternative approach is to capture the essences of the solution but leave the instance details for when the solutions are used. This second approach is the one taken by the Standard Template Library (STL) as an example. But the issue with template libraries is that the groups of individuals who know the library well use it but if an individual does not know it “none” of it gets used. BPP allows for an alternate vision of creating software to solve as specific problem.

Lets take the case of using BPP to serialize objects to and from a database with a mapped structure. So for example if the class below is declared (ignoring the encapsulation issues):

public class Item{
  public float value;
  public int quantity;
  public string description;
  public string partNumber;
}
While serialization is available for this class, serializing to a Binary Large OBject (BLOB) in a database renders the structure of this class inaccessible. A better approach would be to create a database table with a version were the data members of the object are given as field names in a database. For example a table created by the following MySQL query:
create table items (integer quantity, float value,  char(80) description, char(10) partNumber, key(partNumber));
Now we need a convenient way to “serialize” the Java object to the Items table. Interestingly we come across the first discrepancy between the “Serialization” concepts and database concepts. Databases work on four basic query types (insert, update, delete, select). Serialization assumes two modes of operation (writeObject and readObject in Java for example). Simply assuming that any object has the required information for the key to be set can resolve this descrepency. So serialization can be defined as and database insert if the key does not exist otherwise it is an update. Deserialization is simply a select on a given key (or across all keys). The delete in a database is equivalent to serializing a larger structure or a vector of objects and then removing and element. All this is pretty straight forward and relatively easy to implement.

And this is where BPP can help with the tedium. A BPP script can be written which encapsulates this understanding and then generates the application specific code needed to serialize the object to a database. Some additional benefits of this approach is the code generated is very similar to the code that would have been generated by hand and the generated code does not require the capabilities of the generation system. A concrete example might make this more clear. Assume that we are going to capture the structure of the class and table above into a single XML document. This document might have a structure as such:

<table name=”items”>
    <field name=”quantity” type=”integer” />
    <field name=”value” type=”float” />
    <field name=”description” type=”string”  width=”80”/>
    <field name=”partNumber” type=”string” width=”10” />
</table>
So now we have captured the essences of the table (class) in a single form that can be generated into the Java source as well as the create table query, and the needed serialization and deserialization functions. The choice to use database nomenclature instead of object nomenclature is for approachability of existing database developers. A BPP script to generate the class would look like the following assuming JDom is use to parse the XML document:
# table=element.getAttributeValue(“name”);
public class $table {
# Iterator it=element.getChildren(“field”);
# while (it.hasNext()) {
#   type=element.getAttributeValue(“type”);
#   name=element.getAttributeValue(“name”);
#   if (type.equals(“integer”))
       int  $name;
#   else if (type.equals(“float”))
      float $name;
#   else if (type.equals(“string”))
      String $name;
# }
}  
The create table BPP script is very analogous. This is shown below:
# table=element.getAttributeValue(“name”);
create table $table (
# Iterator it=element.getChildren(“field”);
# while (it.hasNext()) {
#   field=(Element)it.next();
#   type=field.getAttributeValue(“type”);
#   name=field.getAttributeValue(“name”);
#   if (type.equals(“integer”))
       integer  $name;
#   else if (type.equals(“float”))
      float $name;
#   else if (type.equals(“string”)) {
#    width=field.getAttributeValue(“width”);
      char($width)  $name;
#   }
#  if (it.hasNext())
  ,
# }
);
Similarly the query to insert the Item into items
Insert into Items (value,quantity,description,partNumber) values (,,’’,’’);
can be generated by the following BPP code:
public void insert(java.sql.Statement s) throws SQLException {
# table=element.getAttributeValue(“name”);
  StringBuffer sb=new StringBuffer(“insert into $table (“);
# it=element.getChildren(“field”);
# while (it.hasNext()) {
#   field=(Element)it.next();
#   name=field.getAttributeValue(“name”);
      sb.append(“$name”);
#  if (it.hasNext())
     sb.append(‘,’);
# }
    sb.append(“) values (“);
# it=element.getChildren(“field”);
# while (it.hasNext()) {
#   field=(Element)it.next();
#   name=field.getAttributeValue(“name”);
#   type=field.getAttributeValue(“type”);
#   if (type.equals(“integer”) || type.equals(“float”))
       sb.append($name);
#   else if (type.equals(“string”)) {
      sb.append(‘\’’); sb.append($width); sb.append(‘\’’);  
#   }
#  if (it.hasNext())
    sb.append(‘,’);
# }
  sb.append(“)”);
  s.ExecuteQuery(sb.toString());
}
The resulting function looks like the following:
void insert(java.sql.Statement s) throws SQLException {
    StringBuffer sb=new StringBuffer(“insert into items (”);
    sb.append(“quantity”);
    sb.append(“,”);
    sb.append(“value”);
    sb.append(“,”);
    sb.append(“description”);
    sb.append(“,”);
    sb.append(“partNumber”);
   sb.append(“) values (“);
    sb.append(quantity);
   sb.append(‘,’);
    sb.append(value);
   sb.append(‘,’);
    sb.append(‘\’’); sb.append(description); sb.append(‘\’’);
   sb.append(‘,’);
    sb.append(‘\’’); sb.append(partNumber); sb.append(‘\’’);
   sb.append(‘)’);
   s.executeQuery(sb.toString());
}
Granted the series of “sb.append” at the top of the insert method could be reduced by using a StringBuffer in the pre-processor code to concatinate the parts together. This was not done for clarity sake. When a bit more care is taken the following code can be generated:
void insert(java.sql.Statement s) throws SQLException {
StringBuffer sb=new StringBuffer(“insert into items (quantity, value, description, partNumber) values (”);
    sb.append(quantity);  
    sb.append(‘,’);
    sb.append(value);   
    sb.append(‘,’);
    sb.append(‘\’’); sb.append(description); sb.append(‘\’’);   
    sb.append(‘,’);
    sb.append(‘\’’); sb.append(partNumber); sb.append(‘\’’);    
   sb.append(‘)’);
   s.executeQuery(sb.toString());
}
Similar approaches can be used for the select, update, delete members. These can then be used together to “serialize” the structure to the database.

A couple of notes are due at this point. First, notice that even though XML is used to document the class/database structure the resulting application does not need any of the JDom tools or even the BPP tools. The application is very similar to what would have been produced by a programmer. Second, note that the above scripts provide an opportunity to use the pre-processor on the pre-processor. The pre-process code that walks through the fields could be written once and named something like “ForAllFields” and then the call to that would replace the following series of lines:

## void ForAllFields() {
# Iterator it=element.getChildren(“field”);
# while (it.hasNext()) {
#   field=(Element)it.next();
#   type=field.getAttributeValue(“type”);
#   name=field.getAttributeValue(“name”);
##}
Along with the standard closing for the while loop with an appropriate name:
## void EndForAllFields() {
#   }
##}
This simple addition will significantly reduce the above scripts. For more information on BPP see Warren MacEvoy's BPP page.