Example of using WebSnap as a source code generator

By: Ivan Babikov

Abstract: WebSnap tool for generating Persistent BOs, EJB Persistent Entity Beans and so on.

Example of using WebSnap as a source code generator

 

Table of contents:

  1. What is this project for?
  2. Advantages of using this generator.
  3. Success story
  4. Writing templates tutorial
  5. Appendix A. Generator tag reference
  6. Appendix B. Examples

 

What is this project for?

    This project demonstrates the following technique:
  1. Generation business object from an arbitrary OO framework expressed in templates.
  2. Using ClientDataSet for isolation from specific data access components in Delphi.
  3. Using interfaces in class design.
  4. Writing cross-platform WebSnap CGI executable using Delphi6 or Kylix2.
  5. Server side JScript programming.

 

Advantages of using this generator

    The generator can be used for:
  1. Generating database dependent language constructions, like Persistent Business Objects.
  2. Generating files for Enterprise Java Beans Persistent Entity Beans:
    1. Generating Remote and Local Interfaces for EJB Persistent Entity Beans.
    2. Generating ejbLoad(), ejbStore() and ejbRemove() methods for EJB Bean-Managed Persistent Entity Beans.
    3. Generating Abstract Persistance Schema as a part of Deployment Descriptor of EJB Container-Managed Persistent Entity Beans.

 

Success story

In the summer of 2001 I stopped working as a Delphi database developer and joined a team working on object oriented database project on Python. My task was writing a vast number of absolutely similar persistent business object (initially 50). After first ten I got tired of such routine work and started thinking about writing a source code generator.

Writing a servlet-like program which simply writes generated source code into output files seemed to be error-prone, because Python language proved to be very capricious about spaces since it uses shifts for definition logical program blocks (instead of curly braces or begin/end operators). And even in case of generation HTML code, page oriented tools (like JSP, ASP and PHP) proved to be much more effective then hard coded generators. So, I turned my head to page-oriented WebSnap.

WebSnap proved to be a good choice, since it has an ability of accessing Delphi DataSets in script and can be compiled as a simple CGI executable. In its turn, VCL data access components can be easily used for getting database structure of almost any database. So all I needed was getting database structure, feeding the structure into DataSets and adding some DataSet adapters for these DataSets.

The structure of the underlying database is got by calling GetTableNames function, which is a part of Database component, making "select *" query for all tables and iterating through FieldDefs array of DataSet.

To let scripts control the generator's execution flow, it reacts on some parametrized tags in OnHTMLTag function. There are 4 tags available: SETTABLE, TEMPLETEFILE, INCLUDE and CONNECTIONparameters.

 

Writing templates tutorial

Mainly the generator is supposed to be used in project-like manner. That means you write project file and put into project references to template files. In project you start iteration through the database tables and generator calls your template files for every table.

 

Example of a project file:

<#CONNECTIONPARAMS%20ConnectionType=IBX%20DatabaseName=./DB/taxi.gdb%20user_name=SYSDBA%20password=masterkey>
<%
var vTables= Modules.WDM.aTables
var e= new Enumerator(vTables.Records)
var vTableName= 'No tables found'
for (; !e.atEnd(); e.moveNext())
{
  vTableName= vTables.TableName.EditText
  Producer.Write('<#SETTABLE%20TableName='+vTableName+'>')%>
<#TEMPLETEFILE%20FileName=bo.asp%20OutputFileNamePattern=*.php%20OutputPath=C:/Apache/htdocs/taxi/BO/>
<#TEMPLETEFILE%20FileName=bo_factory.asp%20OutputFileNamePattern=*_Factory.php%20OutputPath=C:/Apache/htdocs/taxi/BO/><%
  }
%>

The example above shows using of all facilities available in project files like setting connection parameters, calling template tables and setting current table. These tags seem to be the only standard way to transmit parameters from scripts to the generator. For more information about generator tags see Appendix A.

You might have noticed the underlined Modules.WDM.aTables object. I underlined it on purpose to focus your attention on Generator's objects available in script. There are only two: Modules.WDM.aTables and Modules.WDM.aFields. The core of using them is simple: you iterate trough tables than send the current table name to generator via <#SETTABLE> tag and finally iterate through fields.

 

Example of a template file:

<
function CurrentFieldInitialValue()
{        
  switch (vFields.VCLFieldDataType.Value)
  {
   case '1': //ftString
        return "''";
   case '9': //ftDate
        return "'00.00.00'";
   case '10': //ftTime
        return "'00:00'";
   case '11': //ftDateTime
        return "'00.00.00 00:00'";
   case '36': //ftTimeStamp
        return "'00.00.00 00:00'";
   case '2': //ftSmallint
   case '3': //ftInteger
   case '4': //ftWord
   case '6': //ftFloat
   case '7': //ftCurrency
   case '8': //ftBCD
        return "'0'"
   }
 }
%>
class <%=vTableName%> extends BO{
<% var e= new Enumerator(vFields.Records)
   for (; !e.atEnd(); e.moveNext()) {%>
 var $<%=vFields.FieldName.Value%>; <%
  }%>

 function <%=vTableName%>($user_session,$db)
 { $this->BO($user_session,$db);
<% var e= new Enumerator(vFields.Records)
   for (; !e.atEnd(); e.moveNext()) {%>
   $this-><%=vFields.FieldName.Value%>= <%=CurrentFieldInitialValue()%>; <%
   }%>
   }
}

 

Appendix A. Generator tag reference

Changing current table affects values of Modules.WDM.aFields object
TagparametersValueUsage
#CONNECTIONPARAMSConnectionType dbExpress, IBX, ZEOS_Postgres See tables below for more information
#INCLUDEFileNameName of the file to be includedUse * to substitute the name of the current table
#SETTABLETableNameName of the current table
#TEMPLETEFILEFileName
OutputFileNamePatternUse * to substitute the name of the current table<
OutputPathDirectory where you want the output files to be placedOptional

Connection specific parameters.

dbExpress connection specific parameters:
ConnectionName, DriverName.

IBX connection specific parameters:
DatabaseName, user_name, password.

ZEOS Postgres connection specific parameters:
DataBase, Encoding(None,866,Koi8r,Koi8u,Cp1251,Iso88592,Cp1250), Host (by default 5432), Login, Password, Port

NOTE: Since this file is processed by the custom tag HTML processor, do not forget to use %20 instead of space characters.

 

Appendix B. Examples

1.PHP framework

This is a simple eCommerce web site for taxi service. It lets clients make orders, distributes orders to drivers and shows them to drivers.

Requirements:

  1. PHP4
  2. Interbase 6.x or FireBird

Author's remark
Using object generation for PHP proved to be an interesting example, since PHP does not have polymorphism but in this case the generator eliminates this drawback with generated functions.

Disclaimer
I tested this PHP code only under PHP4+Apache for Windows.

 

2.Grant example

Once I needed to grant access to big number of tables to a new user. Using of particular database utility could help but I needed a script. So I used my generator.


All source codes for this generator are available at: http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=17713
Please, share your opinion about this generator and rate it there.


Author: Ivan Babikov

EMail: babikov@mail.ru

WWW: http://www.exskynet.bip.ru/babikov

 


Server Response from: ETNASC01