Somusar/tjpp[tm]

User's Guide

Francesco Aliverti-Piuri

Copyright © 2003-2012 Somusar

      
      
      
      
      
      
      
      
      
      
      
      
      
      

Copyright © 2003-2012 so.mus.ar. s.a.s.
Via Sangallo 30 - 20133 Milan - Italy
All rights reserved.

Unix is a registered trademark in the United States and other countries, licensed exclusively through X/Open Company Limited.

Linux is a registered trademark of Linus Torvalds in the United States and other countries.

Sun, Sun Microsystems, the Sun logo, Solaris, Java, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Symbian and all Symbian-based marks and logos are trademarks of Symbian Software Limited.

Apple and Mac OS are registered trademarks of Apple Computer, Inc. in the United States and other countries.

Intel is a registered trademark of Intel Corporation in the United States and other countries.

PowerPC and CICS are registered trademarks of International Business Machines Corporation in the United States and other countries.

Microsoft, Windows, Visual Basic are either trademarks or registered trademarks of Microsoft Corp. in the United States and/or other countries.

Oracle is a registered trademark, and PL/SQL is a trademark of Oracle Corporation.

SAP and ABAP/4 are registered trademarks of SAP AG in Germany and several other countries.

PostScript is a registered trademark of Adobe Systems Incorporated in the United States and/or other countries.

So.mus.ar, the Somusar logo, Somusar/Software Production Technique, Somusar/Software Production Machine, Somusar/Sisendel, Somusar/Tefigel, Somusar/SoProTech, Somusar/SoProMach, Somusar/Software Entity, Somusar/Software Mold, Somusar/Software Mold Kit, Somusar/Software Mold Building, Somusar/Code Generator Building, Somusar/Generator Building, and Somusar/File Generation Scheme are trademarks of so.mus.ar. s.a.s. in Italy, in the European Union, in the United States of America and other countries.

Other trademarks or service marks referenced herein are property of their respective owners.


Contents
Chapter 1 - Introduction
1.1 - Acknowledgments
Chapter 2 - Overview
2.1 - Architecture
2.2 - Usage
Chapter 3 - Installing tjpp[tm]
Chapter 4 - SimpleClass Example
4.1 - Including files
4.2 - Code generation variables
4.3 - Conditional code generation
4.4 - User macros
4.5 - Tracing
4.6 - Code Examples
Chapter 5 - ComplexClass Example
5.1 - Attaching files
5.2 - Enumerated types
5.3 - Properties
5.4 - Assertions
5.5 - Code Examples
Chapter 6 - Running a Test
6.1 - Code Examples
Chapter 7 - Exercise: Improving Multitier Code Consistency
7.1 - Code Examples
Chapter 8 - Contacting Somusar
8.1 - Requesting Support
Chapter 9 - Further Reading
Appendix A - tjpp Directives and Macros
A.1 - List of available directives
A.2 - List of available macros

Code Examples
Code Example 1 - Input code to generate SimpleClass.java
Code Example 2 - Code generated from SimpleClass.tj
Code Example 3 - A user-defined macro: timestamp
Code Example 4 - Another user-defined macro: perc
Code Example 5 - Input code to generate ComplexClass.java
Code Example 6 - Code generated from ComplexClass.tj
Code Example 7 - Implementation of assert
Code Example 8 - tjpp test class
Code Example 9 - Diagnostic messages: "stderr.txt"
Code Example 10 - Input code to generate Results.java
Code Example 11 - Code generated from Results.tj
Code Example 12 - A macro to generate result-get statements

Tables
Table 1 - Tjpp generic directives
Table 2 - Tjpp property-oriented directives
Table 3 - Tjpp predefined macros
Table 4 - Sample user-defined macros

Chapter 1 - Introduction

This document describes how to install and operate Somusar/tjpp[tm], independently of the underlying operating system and of the edition of Somusar/tjpp[tm].

All Somusar's products are currently available for the following platforms:

The reader should be familiar with the following basic concepts and procedures:

1.1 - Acknowledgments

Special thanks to Salvatore "JVM" Arnone for his contributions in terms of Java expertise, and to Jack Herrington, author of "Code Generation in Action" and editor of Code Generation Network, for openly discussing pros/cons of an alternative generator model for tjpp.

Chapter 2 - Overview

Somusar/tjpp[tm] is a Java[tm] pre-processor and code generator featuring the following functions:

  1. Property-oriented directives to define class properties and generate code related to the list of properties;

  2. File-oriented macro definitions;

  3. Inclusion of header files, with or without processing of their contents;

  4. Conditional generation of code blocks;

  5. Compact directives for boolean assertions and variable tracing print-outs.

With the only exception of item #4 in the above list, all tjpp features are implemented as textual macros and are thus open to any user-defined customization.

Tjpp fits particularly well in text-editor and command-line oriented development shops, allowing to reduce, insulate, and factorize repetitive code blocks and coding practices into parametrical user-defined macros that allow to quickly generate and assemble Java[tm] source files, or parts thereof.

The main advantage of tjpp is the reduction of redundant code, that can be transparently generated and re-generated by means of pre-defined directives and user-defined parametrical macros at file-system level.

Another advantage is the possibility to insulate in external macros syntax constructs subject to change as Java evolves, as shown by directive enumeration. When the new construct becomes officially available, the required changes need be applied only once in the macro, and all ".java" files using that construct can then be regenerated, thus providing higher flexibility and consistency.

To avoid introducing additional constructs in the Java files, tjpp translates ".tj" files into ".java" files, thus leaving untouched the subsequent steps of the software development and management cycles. Adding the ".tj" to ".java" translation to a command-line oriented software production chain should be not an issue.

2.1 - Architecture

Tjpp is a thin shell or ".bat" wrapper around Tefigel, accepting one input file (a ".tj" file) and producing one output file (the corresponding ".java" file). Tefigel is a slim executable file, currently available for Linux®, Mac OS® X, and Windows®. Tefigel is a scripting language expressly designed for code generation. "Tefigel" stands for text file generation language.

The Tefigel code implementing all tjpp's macros and directives is kept in directory "tjpp_lib", while the header files (extension ".tjh") are stored under directory "tjpp_include". Note the clear separation between macro files and header files: each tjpp macro resides in exactly one file under "tjpp_lib", and header files under "tjpp_include" do not define any macro.

2.2 - Usage

After installing tjpp as described in the next chapter, to run it type

   prompt> tjpp YourClass.tj
   prompt> tjpp subdir/AnotherClass.tj
which will produce "YourClass.java" and "subdir/AnotherClass.java" respectively.

Note that each run will overwrite the generated ".java" file, unless you set TJPP_BACKS_UP_JAVA to true in file "tjpp_include/tjpp.defs" to have tjpp save a time-stamped copy of "YourClass.java" into (for example) "YourClass.java-Dec02-12.39".

Tjpp has no command line options or flags. In particular, there is no equivalent to the C/C++ -DSOME_FLAG=some_value or -Isome_include_path preprocessor options.

All tjpp's error and warning messages output by Tefigel are described in "Somusar/SoProMach[tm]: User's Guide ".

Chapter 3 - Installing tjpp[tm]

The software package delivered together with this guide is a file in tar/gzip (in short: tgz) format and can be unpacked by means of utilities such as Winzip® or similar programs.

Alternatively, tgz files can be directly unzipped and expanded using gunzip and gtar, available for practically all platforms. More information on this topic can be found on web page http://www.gzip.org.

The installation of tjpp does not require administrator (or root) privileges; however, a centralized installation may require such privileges in order to share the tjpp package and the related environment variables.

To install tjpp and to verify the installation proceed as described in the "READ_ME.txt" included in the delivery package:

==================================================================

Delivery package of somusar/tjpp[tm] - tefigel Java[tm] pre-processor

Copyright (c) 2003 so.mus.ar. s.a.s. - www.somusar.com

This file last edited on: 03 December 2003

==================================================================

==================================================================
   Installing somusar/tjpp[tm]
==================================================================

To install tjpp, unpack the compressed file in its
installation directory (suggestion: /opt/somusar),
set environment variable TJPP_PATH to the installation
directory and add TJPP_PATH/bin to your PATH.

To verify the installation, go under TJPP_PATH/sample
and run
   tjpp ComplexClass.tj
This command should generate file ComplexClass.java,
containing the code expansion of ComplexClass.tj.

Additional sample files can be preprocessed as follows:
   tjpp subpackage/SimpleClass.tj
   tjpp Results.tj

==================================================================
   somusar/tjpp[tm] package contents
==================================================================
    READ_ME.txt            this file
 
    bin:
        tjpp               executable script for tjpp
        tefigel            executable file for tefigel
	(alternatively, tjpp.bat and tefigel.exe for Windows[r])
 
    tjpp_include:
        copyright.tjh      sample tjpp header file
        header.tjh         sample tjpp header file
        tjpp.defs          repository file for code generation
	                   variables
 
        subinc:
            subhdr.tjh     sample tjpp header file
 
    tjpp_lib:              tjpp macro code files in tefigel
        assert
        attach
        checkhdr
        enumeration
        eofinput
        fileprefix
        flatpath
        gen_warning
        getset
        getters
        include
        init.tfg           tefigel initialization file
        jfileloc
        newfile
        property
        property_get
        property_id
        property_scan
        property_set
        property_type
        setters
	to_string
        trace
        warning
 
        my_macros:         sample user-defined macros
	    get_results
            perc
            timestamp
 
    sample:                sample code for tjpp
        ComplexClass.tj    sample tjpp input file
        Results.tj         sample tjpp input file
        TestJavapp.java    Java test for ComplexClass.java
                           and subpackage/SimpleClass.java

        subpackage:
            SimpleClass.tj sample tjpp input file
 
==================================================================

Chapter 4 - SimpleClass Example

A first example of the code generated by tjpp is provided by the translation of "SimpleClass.tj" into "SimpleClass.java". The most relevant code fragments are described below.

4.1 - Including files

Directive include is similar to the well-known #include of C and C++:

  $include(header.tjh)
By convention, tjpp requires header files to bear the extension ".tjh". Path names are relative to "tjpp_include". Tjpp issues a warning message when it detects multiple inclusions of the same file.

4.2 - Code generation variables

Preprocessing variables are defined and set as follows:

  : MY_TIME_MACRO_ENABLED=1
Tjpp's preferred file for these variables is "tjpp_include/tjpp.defs", but users can freely define additional variables as needed.

4.3 - Conditional code generation

Conditional code generation directly uses Tefigel's instructions IF, ELSE, and ENDIF:

  @ IF MY_TIME_MACRO_ENABLED=1
  //   DATE of preprocessing: $my_macros/timestamp(date)
  //   TIME of preprocessing: $my_macros/timestamp(time)
  @ ELSE
  //   Oops, my time macro is not enabled!
  @ ENDIF

4.4 - User macros

User-defined macros are used as the my_macros/timestamp macro in the following fragment:

  //   DATE of preprocessing: $my_macros/timestamp(date)
The dollar sign "$" instructs tjpp to call macro "my_macros/timestamp" with parameter "date", and replace the macro call in input with its string result in output. The macro file "my_macros/timestamp" is to be found under "tjpp_lib".

Note that the macro can be used even within Java comments, as tjpp is unaware of Java syntax and semantics. The source code of the timestamp macro is commented at the end of this chapter.

Another example of user macro is provided by "ComplexClass.tj", a file presented in detail later in this booklet:

  double d = $my_macros/perc(anInt,1000);
The above line translates to
  double d = ((anInt) * 100.0 / (1000));
The source code of this macro is commented at the end of this chapter.

Tjpp allows to define more powerful macros, generating whole blocks of code. An example is presented later in paragraph "Exercise: Improving Multitier Code Consistency".

4.5 - Tracing

Variable tracing is used as follows:

      public void setAThing( Object aThing ) {
  $       trace(aThing)
          this.aThing = aThing;
      }
and generates the following code:
  public void setAThing( Object aThing ) {
      System.err.println("[T] File subpackage/SimpleClass.java, line 68
(src: subpackage/SimpleClass.tj, 56)");
      System.err.println("[T]    [aThing = '" + aThing + "']");
      this.aThing = aThing;
  }
Note that, for debugging convenience, the trace message reports file name and line number of both ".tj" and ".java" files. Several variables can be traced in one trace, as shown by the following fragment from "ComplexClass.tj":
  $       trace(aRange,aColor)

4.6 - Code Examples

Code Example 1 - Input code to generate SimpleClass.java

Line 1 shows an example of use of a tjpp variable, namely PACKAGE_ROOT, which is set in "tjpp_include/tjpp.defs".
Lines 9-10 use directive $include, referring to files available under "tjpp_include".
Line 12 sets a tjpp variable, which is then used for the conditional code block of lines 13-18.
Lines 14-15 call a user-defined macro from "tjpp_lib", namely tjpp_lib/my_macros/timestamp.
Directive $trace is used on lines 39 and 56.
 
Source code - File "input_code/subpackage/SimpleClass.tj"
    1      package PACKAGE_ROOT.subpackage;
    2      
    3      /**
    4       *   Class SimpleClass:
    5       *
    6       *   A simple software entity.
    7       */
    8      
    9      $include(header.tjh)
   10      $include(subinc/subhdr.tjh)
   11      
   12      : MY_TIME_MACRO_ENABLED=1
   13      @ IF MY_TIME_MACRO_ENABLED=1
   14      //   DATE of preprocessing: $my_macros/timestamp(date)
   15      //   TIME of preprocessing: $my_macros/timestamp(time)
   16      @ ELSE
   17      //   Oops, my time macro is not enabled!
   18      @ ENDIF
   19      
   20      public class SimpleClass {
   21      
   22          private String       aStringOfChar;        
   23          private int          anInt;            
   24          private Object       aThing;             
   25          
   26          /*
   27           *   Get methods
   28           */
   29      
   30          public String getAStringOfChar() {
   31              return aStringOfChar;
   32          }
   33      
   34          public int getAnInt() {
   35              return anInt;
   36          }
   37      
   38          public Object getAThing() {
   39      $       trace(aThing)
   40              return aThing;
   41          }
   42      
   43          /*
   44           *   Set methods
   45           */
   46      
   47          public void setAStringOfChar( String aStringOfChar ) {
   48              this.aStringOfChar = aStringOfChar;
   49          }
   50      
   51          public void setAnInt( int anInt ) {
   52              this.anInt = anInt;
   53          }
   54      
   55          public void setAThing( Object aThing ) {
   56      $       trace(aThing)
   57              this.aThing = aThing;
   58          }
   59      
   60      }
	       

Code Example 2 - Code generated from SimpleClass.tj

Lines 1-3 and 70-72 contain a warning message automatically generated by tjpp.
Line 4 shows that PACKAGE_ROOT has been replaced by com.somusar.tjpptest, as expected.
The $include directives have produced code lines 12-22.
Lines 24 and 25 contain the results returned by macro my_macros/timestamp.
Lines 46-47 and 64-65 correspond to the two $traces of "subpackage/SimpleClass.tj".
 
Source code - File "generated_code/subpackage/SimpleClass.java"
    1      // WARNING: file "subpackage/SimpleClass.java" generated from "subpackage/SimpleClass.tj"
    2      //          Changes should be applied on the source file.
    3      
    4      package com.somusar.tjpptest.subpackage;
    5      
    6      /**
    7       *   Class SimpleClass:
    8       *
    9       *   A simple software entity.
   10       */
   11      
   12                                 // begin include "header.tjh"
   13      //
   14      // Sample header file for Java preprocessor
   15      //
   16                                 //   end include "header.tjh"
   17                                 // begin include "subinc/subhdr.tjh"
   18      //
   19      // Sample header file for Java preprocessor from a subdirectory
   20      // of include root directory "tjpp_inst/tjpp_include"
   21      //
   22                                 //   end include "subinc/subhdr.tjh"
   23      
   24      //   DATE of preprocessing: timestamp for "date": Wed Dec 03 2003
   25      //   TIME of preprocessing: timestamp for "time": 17:35:16.844
   26      
   27      public class SimpleClass {
   28      
   29          private String       aStringOfChar;        
   30          private int          anInt;            
   31          private Object       aThing;             
   32          
   33          /*
   34           *   Get methods
   35           */
   36      
   37          public String getAStringOfChar() {
   38              return aStringOfChar;
   39          }
   40      
   41          public int getAnInt() {
   42              return anInt;
   43          }
   44      
   45          public Object getAThing() {
   46              System.err.println("[T] File subpackage/SimpleClass.java, line 46 (src: subpackage/SimpleClass.tj, 39)");
   47              System.err.println("[T]    [aThing = '" + aThing + "']");
   48              return aThing;
   49          }
   50      
   51          /*
   52           *   Set methods
   53           */
   54      
   55          public void setAStringOfChar( String aStringOfChar ) {
   56              this.aStringOfChar = aStringOfChar;
   57          }
   58      
   59          public void setAnInt( int anInt ) {
   60              this.anInt = anInt;
   61          }
   62      
   63          public void setAThing( Object aThing ) {
   64              System.err.println("[T] File subpackage/SimpleClass.java, line 64 (src: subpackage/SimpleClass.tj, 56)");
   65              System.err.println("[T]    [aThing = '" + aThing + "']");
   66              this.aThing = aThing;
   67          }
   68      
   69      }
   70      
   71      // WARNING: file "subpackage/SimpleClass.java" generated from "subpackage/SimpleClass.tj"
   72      //          Changes should be applied on the source file.
	       

Code Example 3 - A user-defined macro: timestamp

Line 1 defines the interface of this macro, which expects one parameter called "what".
Lines 7 and 9 call Tefigel's built-in functions DATE and TIME.
Line 11 sets the return value of this macro to the string on the right side of the assignment.
 
Source code - File "input_code/tjpp_lib/my_macros/timestamp"
    1      @ INTERFACE(what)
    2      | 
    3      |   Sample user-defined macro, returning a string
    4      |   with a time stamp, as requested via parameter "what"
    5      |
    6      @ IF what=date
    7      @    SET TS=$DATE
    8      @ ELSE
    9      @    SET TS=$TIME
   10      @ ENDIF
   11      @ RETVALUE=timestamp for "what": TS
	       

Code Example 4 - Another user-defined macro: perc

This tjpp macro is equivalent to the following C #define:
  #define perc(a,b) ((a) * 100.0 / (b))
A major advantage of tjpp macros is that they reside in individual files and are called by means of their file-system path name, relative to "tjpp_lib". Moreover, they can accept a variable number of arguments. This particular macro expects two arguments, referred to by means of local variables a and b, as specified on line 1.
 
Source code - File "input_code/tjpp_lib/my_macros/perc"
    1      @ INTERFACE(a,b)
    2      | 
    3      |   Sample user-defined macro, returning a code string
    4      |   to compute the percentage on given arguments.
    5      |
    6      @ RETVALUE=((a) * 100.0 / (b))
	       

Chapter 5 - ComplexClass Example

Translation of "ComplexClass.tj" into "ComplexClass.java" provides a more complex example of code generated by tjpp. The most significant code fragments are described below.

5.1 - Attaching files

Directive attach is similar to include, but instructs tjpp to simply copy the contents of the attached file, without processing it.

  $attach(copyright.tjh)

5.2 - Enumerated types

Directive enumeration provides a means to define enumerated types:

  $   enumeration(Color,%
         RED,           %
         GREEN,         %
         BLUE           %
      )
The percent sign "%" is tjpp's line concatenation operator.

The above directive generates the following code:

  // Map enum 'Color' onto an int with a set of values
  public static final int RED                = 0;
  public static final int GREEN              = 1;
  public static final int BLUE               = 2;
User-defined numeric values can also be provided as follows:
  $   enumeration(Color,%
         RED=1,         %
         GREEN=2,       %
         BLUE=4         %
  )

5.3 - Properties

Directives property, getters, setters and to_string allow to concisely define the set of properties of a class and produce a toString method:

  $   property(int,      a_unique_id,      readonly)
  $   property(Object,   a_thing)

  $   getters
  $   setters
  $   to_string
Directive property accepts a Java type, an identifier (in lower case letters, digits, and underscores) and an optional readonly flag. The list of properties is then scanned by getter and setter to generate the accessors and mutators. No mutator is generated for properties declared as readonly. In a similar way, directive to_string scans the list of properties to generate the toString method. The fragment above translates to the following Java code:
    private int          aUniqueId;     // read-only
    private Object       aThing;

    /*
     *   Get methods
     */

    public int getAUniqueId() {
        return aUniqueId;
    }

    public Object getAThing() {
        return aThing;
    }

    /*
     *   Set methods
     */

    public void setAThing( Object aThing ) {
        this.aThing = aThing;
    }

    public String toString() {
        String s = "[" +
                   " aUniqueId = '" + aUniqueId + "'" +
                   " aThing = '" + aThing + "'" +
                   " ]";
        return s;
    }

5.4 - Assertions

The assert directive of tjpp provides a rather mild implementation of assertions, in comparison with regular Java assertions. The generated code checks the assertion and prints a message similar to the trace message if the asserted condition evaluates to false, raising neither errors, nor exceptions. The following fragments show the input to, and output from, tjpp.

Input:

  $       assert(aRange >= 0 && aRange < 20000)
Output:
  {
      if (! (aRange >= 0 && aRange < 20000)) {
          System.err.println("[A] -------------");
          System.err.println("[A] --- File ComplexClass.java, line 153 
(src: ComplexClass.tj, 54)");
          System.err.println("[A] --- Assertion 'aRange >= 0 && aRange 
< 20000' failed");
          System.err.println("[A] -------------");
      }
  }
As for most tjpp directives, it is also possible to customize this directive, for instance to add code that prints a stack trace or raises an error. The macro source code is commented at the end of this chapter.

5.5 - Code Examples

Code Example 5 - Input code to generate ComplexClass.java

Line 1 uses directive $attach to include a copyright file without any processing, ensuring that the contents of the include file is faithfully copied to the generated file.
Lines 5 and 13 use tjpp variable PACKAGE_ROOT.
Lines 18-22 contain a tjpp comment.
Lines 23-42 use the property-oriented directives of tjpp, namely enumeration, property, getters, and setters.
Variable trace directives are used on lines 53, 66-67, 69-70: in particular, tracing is switched off between lines 66 and 68.
Line 54 shows an example of $assert.
A user-defined macro, "tjpp_include/my_macros/perc", is used on line 68.
Directive to_string is used on line 74.
 
Source code - File "input_code/ComplexClass.tj"
    1      $attach(copyright.tjh)
    2      $include(header.tjh)
    3      $include(subinc/subhdr.tjh)
    4      
    5      package PACKAGE_ROOT;
    6      
    7      /**
    8       *   Class ComplexClass:
    9       *
   10       *   A software entity with several fields and collections.
   11       */
   12      
   13      import PACKAGE_ROOT.subpackage.SimpleClass;
   14      import java.util.Date;
   15      
   16      public class ComplexClass extends SimpleClass {
   17      
   18      |---
   19      |   This is a tjpp comment that will not appear in the
   20      |   generated Java file. The "%" in the lines below is
   21      |   tjpp's line-concatenation operator.
   22      |---
   23      $   enumeration(Color,%
   24             RED,           %
   25             GREEN,         %
   26             BLUE           %
   27          )
   28      
   29      $   property(boolean,  a_bool)
   30      $   property(int,      a_color)
   31      $   property(double,   a_float)
   32      $   property(int,      a_range)
   33      $   property(String,   a_string)
   34      $   property(Date,     a_time)
   35      $   property(int,      a_unique_id,      readonly)
   36      $   property(int,      an_int,           readonly)
   37      $   property(int,      another_color,    readonly)
   38      $   property(Object,   a_thing)
   39      $   property(int [][], an_int_array)
   40          
   41      $   getters
   42      $   setters
   43      
   44          /**
   45           *   Method 'A function'
   46           */
   47      
   48          public boolean aFunction (
   49                          int aRange,
   50                          int aColor
   51                 )
   52          {
   53      $       trace(aRange,aColor)
   54      $       assert(aRange >= 0 && aRange < 20000)
   55              return true;
   56          }
   57      
   58          /**
   59           *   Method 'A function'
   60           */
   61      
   62          public double aFunction (
   63                          int anInt
   64                 )
   65          {
   66      : TRACE_SWITCH=off
   67      $       trace(anInt)
   68              double d = $my_macros/perc(anInt,1000);
   69      : TRACE_SWITCH=on
   70      $       trace(d)
   71              return d;
   72          }
   73      
   74      $   to_string
   75      
   76      }
	       

Code Example 6 - Code generated from ComplexClass.tj

The $attached copyright file has been copied to lines 4-8.
Lines 34-37 show the code generated by directive enumeration.
Lines 39-49 result from directive member.
Lines 51-98 result from directive getters.
Lines 99-134 result from directive setters: no set method has been generated for properties declared read-only.
The values of two traced variables are printed out on lines 145-147.
Lines 148-155 show the code generated by directive assert.
Line 167 contains the result of $my_macros/perc(anInt),1000.
Lines 168-169 trace variable d, while no tracing statements have been generated for parameter anInt, as $trace(anInt) followed a ": TRACE_SWITCH=off" directive.
Lines 173-188 show the code generated by directive to_string.
 
Source code - File "generated_code/ComplexClass.java"
    1      // WARNING: file "ComplexClass.java" generated from "ComplexClass.tj"
    2      //          Changes should be applied on the source file.
    3      
    4      //
    5      // Sample copyright file for Java preprocessor
    6      //
    7      //    Copyright (c) _____________ , 2003 - All rights reserved.
    8      //
    9                                 // begin include "header.tjh"
   10      //
   11      // Sample header file for Java preprocessor
   12      //
   13                                 //   end include "header.tjh"
   14                                 // begin include "subinc/subhdr.tjh"
   15      //
   16      // Sample header file for Java preprocessor from a subdirectory
   17      // of include root directory "tjpp_inst/tjpp_include"
   18      //
   19                                 //   end include "subinc/subhdr.tjh"
   20      
   21      package com.somusar.tjpptest;
   22      
   23      /**
   24       *   Class ComplexClass:
   25       *
   26       *   A software entity with several fields and collections.
   27       */
   28      
   29      import com.somusar.tjpptest.subpackage.SimpleClass;
   30      import java.util.Date;
   31      
   32      public class ComplexClass extends SimpleClass {
   33      
   34          // Map enum 'Color' onto an int with a set of values
   35          public static final int RED                = 0;
   36          public static final int GREEN              = 1;
   37          public static final int BLUE               = 2;
   38      
   39          private boolean      aBool;
   40          private int          aColor;
   41          private double       aFloat;
   42          private int          aRange;
   43          private String       aString;
   44          private Date         aTime;
   45          private int          aUniqueId;     // read-only
   46          private int          anInt;         // read-only
   47          private int          anotherColor;  // read-only
   48          private Object       aThing;
   49          private int          anIntArray[][];
   50          
   51          /*
   52           *   Get methods
   53           */
   54      
   55          public boolean getABool() {
   56              return aBool;
   57          }
   58      
   59          public int getAColor() {
   60              return aColor;
   61          }
   62      
   63          public double getAFloat() {
   64              return aFloat;
   65          }
   66      
   67          public int getARange() {
   68              return aRange;
   69          }
   70      
   71          public String getAString() {
   72              return aString;
   73          }
   74      
   75          public Date getATime() {
   76              return aTime;
   77          }
   78      
   79          public int getAUniqueId() {
   80              return aUniqueId;
   81          }
   82      
   83          public int getAnInt() {
   84              return anInt;
   85          }
   86      
   87          public int getAnotherColor() {
   88              return anotherColor;
   89          }
   90      
   91          public Object getAThing() {
   92              return aThing;
   93          }
   94      
   95          public int[][] getAnIntArray() {
   96              return anIntArray;
   97          }
   98      
   99          /*
  100           *   Set methods
  101           */
  102      
  103          public void setABool( boolean aBool ) {
  104              this.aBool = aBool;
  105          }
  106      
  107          public void setAColor( int aColor ) {
  108              this.aColor = aColor;
  109          }
  110      
  111          public void setAFloat( double aFloat ) {
  112              this.aFloat = aFloat;
  113          }
  114      
  115          public void setARange( int aRange ) {
  116              this.aRange = aRange;
  117          }
  118      
  119          public void setAString( String aString ) {
  120              this.aString = aString;
  121          }
  122      
  123          public void setATime( Date aTime ) {
  124              this.aTime = aTime;
  125          }
  126      
  127          public void setAThing( Object aThing ) {
  128              this.aThing = aThing;
  129          }
  130      
  131          public void setAnIntArray( int anIntArray[][] ) {
  132              this.anIntArray = anIntArray;
  133          }
  134      
  135      
  136          /**
  137           *   Method 'A function'
  138           */
  139      
  140          public boolean aFunction (
  141                          int aRange,
  142                          int aColor
  143                 )
  144          {
  145              System.err.println("[T] File ComplexClass.java, line 145 (src: ComplexClass.tj, 53)");
  146              System.err.println("[T]    [aRange = '" + aRange + "']");
  147              System.err.println("[T]    [aColor = '" + aColor + "']");
  148              {
  149                  if (! (aRange >= 0 && aRange < 20000)) {
  150                      System.err.println("[A] -------------");
  151                      System.err.println("[A] --- File ComplexClass.java, line 149 (src: ComplexClass.tj, 54)");
  152                      System.err.println("[A] --- Assertion 'aRange >= 0 && aRange < 20000' failed");
  153                      System.err.println("[A] -------------");
  154                  }
  155              }
  156              return true;
  157          }
  158      
  159          /**
  160           *   Method 'A function'
  161           */
  162      
  163          public double aFunction (
  164                          int anInt
  165                 )
  166          {
  167              double d = ((anInt) * 100.0 / (1000));
  168              System.err.println("[T] File ComplexClass.java, line 168 (src: ComplexClass.tj, 70)");
  169              System.err.println("[T]    [d = '" + d + "']");
  170              return d;
  171          }
  172      
  173          public String toString() {
  174              String s = "[" +
  175                         " aBool = '" + aBool + "'" +
  176                         " aColor = '" + aColor + "'" +
  177                         " aFloat = '" + aFloat + "'" +
  178                         " aRange = '" + aRange + "'" +
  179                         " aString = '" + aString + "'" +
  180                         " aTime = '" + aTime + "'" +
  181                         " aUniqueId = '" + aUniqueId + "'" +
  182                         " anInt = '" + anInt + "'" +
  183                         " anotherColor = '" + anotherColor + "'" +
  184                         " aThing = '" + aThing + "'" +
  185                         " anIntArray = '" + anIntArray + "'" +
  186                         " ]";
  187              return s;
  188          }
  189      
  190      }
  191      
  192      // WARNING: file "ComplexClass.java" generated from "ComplexClass.tj"
  193      //          Changes should be applied on the source file.
	       

Code Example 7 - Implementation of assert

Generation of assertion code is controlled by tjpp's variable ASSERTION_SWITCH (lines 11-13).
Line 14 defines a string pattern to be printed out by each assertion message.
Line 16 retrieves the current line numbers of both input (".tj") and output (".java") files.
The assertion expression passed as argument to assert is referred to by means of tjpp's variable REG_ALL on lines 17 and 20.
The code fragment pattern generated for each assert is defined by lines 15 and 17-23, and can easily be customized as needed, for instance adding error-raising statements.
 
Source code - File "input_code/tjpp_lib/assert"
    1      @ INTERFACE(...)
    2      |
    3      |   Generate a block of statements to check an assertion.
    4      |   The assertion expression is passed as one or more arguments
    5      |   and used below as REG_ALL.
    6      |   When an assertion evaluates to false, the generated code
    7      |   prints out a trace message with source file and line, then
    8      |   continues normal execution flow.
    9      |   No code is generated if ASSERTION_SWITCH is not "on".
   10      |
   11      @ IF ASSERTION_SWITCH#on
   12      @    QUIT
   13      @ ENDIF
   14      @ SET ASSERTIONBANNER=[A] ---
   15              {
   16      @ SET FILELOC=$jfileloc
   17                  if (! (REG_ALL)) {
   18                      System.err.println("ASSERTIONBANNER----------");
   19                      System.err.println("ASSERTIONBANNER FILELOC");
   20                      System.err.println("ASSERTIONBANNER Assertion 'REG_ALL' failed");
   21                      System.err.println("ASSERTIONBANNER----------");
   22                  }
   23              }
	       

Chapter 6 - Running a Test

A plain Java file, "TestJavapp.java", contains a test program for "SimpleClass.java" and "ComplexClass.java". Running the test produces the diagnostic System.err messages listed and commented in "stderr.txt".

6.1 - Code Examples

Code Example 8 - tjpp test class

Line 16 causes an assertion to fail and a trace message to be printed out.
Each line between 17 and 20 produces one trace message.
 
Source code - File "input_code/TestJavapp.java"
    1      package com.somusar.tjpptest;
    2      
    3      import com.somusar.tjpptest.ComplexClass;
    4      import com.somusar.tjpptest.subpackage.SimpleClass;
    5      
    6      public class TestJavapp {
    7      
    8         public static void main(String[] args) {
    9      
   10            SimpleClass  s = new SimpleClass();
   11            ComplexClass c = new ComplexClass();
   12            double  d;
   13            boolean b;
   14            Object  o;
   15      
   16            b = c.aFunction(20000, ComplexClass.RED);
   17            b = c.aFunction(10000, ComplexClass.GREEN);
   18            d = c.aFunction(12);
   19            s.setAThing(c);
   20            o = s.getAThing();
   21         }
   22      }
	       

Code Example 9 - Diagnostic messages: "stderr.txt"

Lines 1-7 result from line 16 of TestJavapp.java.
Lines 8-10 result from line 17 of the same file.
Lines 11-12 result from line 18.
Lines 13-14 result from line 19.
Lines 15-16 result from line 20.
 
Source code - File "generated_code/stderr.txt"
    1      [T] File ComplexClass.java, line 145 (src: ComplexClass.tj, 53)
    2      [T]    [aRange = '20000']
    3      [T]    [aColor = '0']
    4      [A] -------------
    5      [A] --- File ComplexClass.java, line 149 (src: ComplexClass.tj, 54)
    6      [A] --- Assertion 'aRange >= 0 && aRange < 20000' failed
    7      [A] -------------
    8      [T] File ComplexClass.java, line 145 (src: ComplexClass.tj, 53)
    9      [T]    [aRange = '10000']
   10      [T]    [aColor = '1']
   11      [T] File ComplexClass.java, line 168 (src: ComplexClass.tj, 70)
   12      [T]    [d = '1.2']
   13      [T] File subpackage/SimpleClass.java, line 64 (src: subpackage/SimpleClass.tj, 56)
   14      [T]    [aThing = '[ aBool = 'false' aColor = '0' aFloat = '0.0' aRange = '0' aString = 'null' aTime = 'null' aUniqueId = '0' anInt = '0' anotherColor = '0' aThing = 'null' anIntArray = 'null' ]']
   15      [T] File subpackage/SimpleClass.java, line 46 (src: subpackage/SimpleClass.tj, 39)
   16      [T]    [aThing = '[ aBool = 'false' aColor = '0' aFloat = '0.0' aRange = '0' aString = 'null' aTime = 'null' aUniqueId = '0' anInt = '0' anotherColor = '0' aThing = 'null' anIntArray = 'null' ]']
	       

Chapter 7 - Exercise: Improving Multitier Code Consistency

Multitier applications replicate the same data item, such as a "Last Name", at various levels: database tables, Java classes (for both business logic and system infrastructure), user interface dialogs.

A familiar example of this is shown by the following code fragment, where data items retrieved from a database are copied to Java variables:

  // Get results from "results" by column name
  int rCustId = results.getInt("CUST_ID");
  String rFirstName = results.getString("FIRST_NAME");
  String rLastName = results.getString("LAST_NAME");
  float rBalance = results.getFloat("BALANCE");
  String rEmail = results.getString("EMAIL");
Similar code fragments are frequent and lend themselves to be generated by a tjpp macro. The new user-defined macro will directly generate a block of code, instead of returning a short string of code as do my_macro/timestamp and my_macro/perc.

The new macro my_macro/get_results is commented below, as are the input "Results.tj" and output "Results.java" files. Input and output fragments are listed below.

Input:

  : MY_MEMBERS=int/cust_id       ,%
               String/first_name ,%
               String/last_name  ,%
               float/balance     ,%
               String/email
  $   my_macros/get_results(BY_NUMBER,rs,MY_MEMBERS)

  $   my_macros/get_results(BY_NAME,results,MY_MEMBERS)
Output:
  int      rCustId     = rs.getInt(    1);
  String   rFirstName  = rs.getString( 2);
  String   rLastName   = rs.getString( 3);
  float    rBalance    = rs.getFloat(  4);
  String   rEmail      = rs.getString( 5);

  int      rCustId     = results.getInt(    "CUST_ID");
  String   rFirstName  = results.getString( "FIRST_NAME");
  String   rLastName   = results.getString( "LAST_NAME");
  float    rBalance    = results.getFloat(  "BALANCE");
  String   rEmail      = results.getString( "EMAIL");
An alternative and more exhaustive solution to the problems deriving from multitier data redundancy is discussed in booklet "somusar/SoProTech: A Sample Project".

7.1 - Code Examples

Code Example 10 - Input code to generate Results.java

Line 8 uses column numbers to get the query result values.
Line 11 uses column names to get the query result values.
Note that reuse of tjpp variable MY_MEMBERS can help increase consistency across different sections or classes of Java code.
 
Source code - File "input_code/Results.tj"
    1      : MY_MEMBERS=int/cust_id       ,%
    2                   String/first_name ,%
    3                   String/last_name  ,%
    4                   float/balance     ,%
    5                   String/email      ,%
    6                   wrongType/sthg_else
    7              // Get results from "rs" by column number
    8      $       my_macros/get_results(BY_NUMBER,rs,MY_MEMBERS)
    9      
   10              // Get results from "results" by column name
   11      $       my_macros/get_results(BY_NAME,results,MY_MEMBERS)
	       

Code Example 11 - Code generated from Results.tj

Lines 5-10 result from calling my_macro/get_results with mode BY_NUMBER.
Lines 13-18 result from calling my_macro/get_results with mode BY_NAME.

Note that a wrongType, supplied to get_results, purposely produced the wrong statements of lines 10 and 18, and caused tjpp to issue a warning message. The Java compiler would then detect the error and the generated code would not be compiled.

 
Source code - File "generated_code/Results.java"
    1      // WARNING: file "Results.java" generated from "Results.tj"
    2      //          Changes should be applied on the source file.
    3      
    4              // Get results from "rs" by column number
    5              int         rCustId     = rs.getInt(    1);
    6              String      rFirstName  = rs.getString( 2);
    7              String      rLastName   = rs.getString( 3);
    8              float       rBalance    = rs.getFloat(  4);
    9              String      rEmail      = rs.getString( 5);
   10              wrongType   rSthgElse   = rs.get UNKNOWN (      6);
   11      
   12              // Get results from "results" by column name
   13              int         rCustId     = results.getInt(       "CUST_ID");
   14              String      rFirstName  = results.getString(    "FIRST_NAME");
   15              String      rLastName   = results.getString(    "LAST_NAME");
   16              float       rBalance    = results.getFloat(     "BALANCE");
   17              String      rEmail      = results.getString(    "EMAIL");
   18              wrongType   rSthgElse   = results.get UNKNOWN ( "STHG_ELSE");
   19      
   20      // WARNING: file "Results.java" generated from "Results.tj"
   21      //          Changes should be applied on the source file.
	       

Code Example 12 - A macro to generate result-get statements

This macro generates result-set getXXX statements from a parametric source variable for the type/id pairs supplied as arguments.
A mode parameter specifies whether the getXXX should use the column name or column number.
 
Source code - File "input_code/tjpp_lib/my_macros/get_results"
    1      @ INTERFACE(mode,source)
    2      |
    3      |   Generate statements in the form (mode = BY_NUMBER) 
    4      |       int         rCustId      = source.getInt(1);
    5      |   or (mode = BY_NAME) 
    6      |       int         rCustId      = source.getInt("CUST_ID");
    7      |   Actually, more arguments are supplied, namely a 
    8      |   list of type/id arguments, like in "int/cust_id".
    9      |
   10      @ DASH ^
   11      |   Create a mapping between Java types and getXXX accessors
   12      @ SET     jmap^int=Int
   13      @ SET   jmap^float=Float
   14      @ SET  jmap^double=Double
   15      @ SET  jmap^String=String
   16      @ SET jmap^boolean=Boolean
   17      |   Scan list of type/id pairs, skipping mode and source
   18      @ SET I=2
   19      @ WHILE I<REG_COUNT
   20      @    SET FIELD=REG_^I
   21      |    Strip leading and trailing blanks
   22      @    SET FIELD=$WORD(FIELD,0)
   23      |    Retrieve type
   24      @    SET JTYPE=$FIELD(FIELD,0,/)
   25      |    Retrieve identifier
   26      @    SET   JID=$FIELD(FIELD,1,/)
   27      |    Check if type mapping is known, issue a warning otherwise
   28      |    and propagate error into Java code
   29      @    SET JRESTYPE=$VALUE(jmap^JTYPE)
   30      @    IF JRESTYPE~jmap
   31      @       SET JRESTYPE= UNKNOWN 
   32      $       warning($jfileloc(src_only): don't know how to map type "JTYPE")
   33      @    ENDIF
   34      |    Select mode of getXXX
   35      @    IF mode=BY_NAME
   36      @       SET JKEY="$MAKE_ID(JID,ABC_DEF)"
   37      @    ELSE
   38      @       SET JKEY=I
   39      @       SUB JKEY 1
   40      @    ENDIF
   41      |    Prepare a local identifier
   42      @    SET JID=$MAKE_ID(r_^JID,abcDef)
   43      |    Prepare right-hand side of assignment
   44      @    SET JVAL=source.get^JRESTYPE(      JKEY)
   45      |    Generate tab-aligned code
   46      @    ECHO $TABS(        JTYPE   JID     = JVAL;,8,20,32,48)
   47      @    ADD I 1
   48      @ ENDWHILE
   49      @ DASH
	       

Chapter 8 - Contacting Somusar

To request any type of information concerning the SoProTech[tm] or the SoProMach[tm], please fill in the appropriate form at http://www.somusar.com/contact specifying, beside your question or questions, the requested contact data.

8.1 - Requesting Support

To request support for any problem concerning tjpp, licensees should fill in form http://www.somusar.com/contact/problem_report, specifying, among other contact data, the following information:

After validation of submitted support requests a confirmation email is sent to the address of the Somusar licensee. Additional information exchange about problem resolution is generally managed via email.

Chapter 9 - Further Reading

Additional information on the different aspects of the Somusar/Software Production Technique[tm] can be found in the other volumes of the Somusar/SoProTech[tm] Booklet Series, listed below.

Vol. I - somusar/SoProTech: An Introduction

An introduction to the Somusar/Software Production Technique[tm], a new, fast, and efficient technology to make high-quality multifacet software.

Vol. II - somusar/SoProTech: A Sample Project

Description of a sample project, serving as a proof-of-concept for the Somusar/Software Production Technique[tm], and the Somusar/Sisendel[tm] and Somusar/Tefigel[tm] languages. A few code examples are provided and demonstrate the practical applicability of the technique.

Vol. III - somusar/Sisendel: A Tutorial Introduction

A tutorial introduction to Somusar/Sisendel[tm], describing all features of the simple software entity design language. Several code examples practically demonstrate the conciseness and flexibility of the language.

Vol. IV - somusar/Tefigel: A Tutorial Introduction

An introduction to the syntax, semantics, and usage of Somusar/Tefigel[tm], including a vast set of code examples, illustrating the powerful features of the text file generation language.

Vol. V - somusar/Sisendel: Reference Guide

Sisendel reference guide: official definition of syntax and semantics of the Somusar/Sisendel[tm] language.

Vol. VI - somusar/Tefigel: Reference Guide

Tefigel reference guide: official definition of syntax and semantics of the Somusar/Tefigel[tm] language.

Vol. VII - somusar/SoProMach: User's Guide

The Somusar/Software Production Machine[tm] User's Guide. How to install and operate SoProMach.

Vol. IX - Code Generation Somusar Style

Proof-of-concept samples of what you can generate with Somusar/SoProMach[tm].

Appendix A - tjpp Directives and Macros

In summary, the current (December 2003) implementation of tjpp provides the directives and macros listed in the following tables.

A.1 - List of available directives

Table 1 - Tjpp generic directives

Directive Description
:IDENTIFIER=value Defines a tjpp variable IDENTIFIER, setting it to the given value. Subsequent references to IDENTIFIER will be replaced by value, even within quotes
@ IF ...
@ ELSE
@ ENDIF
Conditional code block generation. This is a Tefigel construct, and is documented at http://somusar.com/doc/booklets/tefigel_ref.
$include(filename) Includes filename in the generated file, processing its contents
$attach(filename) Includes filename in the generated file, without processing its contents
$trace(var1[,var2...]) Generates code to print out on System.err the value of each variable var1, var2, ...
$assert(expression) Generates code to evaluate the assertion defined by the boolean expression and perform an action if it evaluates to false. By default the action is a tracing message printed out on System.err

Generation of code for $asserts and $traces is controlled respectively by tjpp's variables ASSERTION_SWITCH and TRACE_SWITCH, which by default are both switched on.

Table 2 - Tjpp property-oriented directives

Directive Description
$property(type,id[,readonly]) Generates code to declare a class property of the given Java type, possibly non-modifiable (when readonly is specified). The identifier id should only contain lower case letters, decimal digits, and underscores, as in this_is_a_valid_identifier.
If TJPP_PROPERTY_MAKES_GSETTERS is set to true, generates also a getter method, and a setter method for modifiable properties
$getters Generates getter methods for all properties declared via directive $property, unless TJPP_PROPERTY_MAKES_GSETTERS is set to true
$setters Generates setter methods for all modifiable properties declared via directive $property, unless TJPP_PROPERTY_MAKES_GSETTERS is set to true
$to_string Generates a toString method based on the property list
$enumeration(enum_descr, %
    VALUE_1[=num_1], %
    VALUE_2[=num_2],...)
Generates code to declare a pseudo-enumeration type described by enum_descr and defined by symbols VALUE_1, VALUE_2, ... Numeric values num_1, num_2, ..., can optionally be associated with the corresponding symbols

A.2 - List of available macros

Tjpp provides the library and user-defined macros listed below. File names are relative to "tjpp_lib".

Table 3 - Tjpp predefined macros

File and macro name Description
checkhdr Verifies that a header file complies with the ".tjh" naming convention
eofinput Tefigel HOOK routine for end-of-file condition
fileprefix Strips a given extension from a given pathname
flatpath Calls fileprefix and replaces "/" with "_"
gen_warning Generates a Java comment with a "generated-file" warning
getset Generates an accessor or a modifier for a given property
jfileloc Returns the file/line location of current ".tj" and (optionally) ".java" files
newfile Tefigel HOOK routine for beginning-of-file condition
property_get Generates the accessor for a given property
property_id Returns the identifier of a given property
property_scan Scans the list of properties applying a given property processor (another tjpp macro)
property_set Generates the modifier for a given property
property_type Returns the type of a given property
warning Issues a generation-time warning message

Table 4 - Sample user-defined macros

File and macro name Description
my_macros/get_results Generate a block of result.getXXX statements
my_macros/perc Returns a code string that calculates the percentage of the given parameters
my_macros/timestamp Returns a time-stamp string