Skip to content

Code Generation

Steve Ives edited this page Apr 1, 2020 · 28 revisions

Harmony Core Logo

Code Generation

Almost all Harmony Core development environments rely heavily on the automatic generation of source code by CodeGen.

You don't need to be a CodeGen expert to be successful with Harmony Core development, but it does help to have a basic understanding of how CodeGen works. That's what you will find in this document.

What is CodeGen

CodeGen is a tool that software developers working in a Synergy Development Environment can use to generate source code. That code might be Synergy DBL code, or might be source code for some other language. CodeGen is not restricted to producing code for any particular development environment or programming language.

Of course, you can’t just use CodeGen to generate any piece of source code that you can imagine. Before code can be generated a developer must declare the rules that define how a given piece of source code should be created. These rules are defined in template files. CodeGen interprets the code and instructions that a developer has defined in a template file in order to produce useful output.

Defining rules in a template file is only part of the story though. To be really useful CodeGen also needs to have another source of information that defines a context for what is to be generated.

Most software applications revolve around the collection, presentation, manipulation, and storage of data. That data is ultimately stored in some type of persistent storage such as in a collection of data files, or in tables in a relational database. When developers work on a particular piece of source code they combine the knowledge that they have about an application's data (metadata) with rules or "business logic", in order to create source code that addresses a particular requirement. CodeGen does the same thing.

When developers work in Synergy/DE they have access to an excellent source of metadata that is called the Synergy/DE Repository. A repository holds extensive information about the data structures used by an application, and the attributes of those data structures. A repository can also contain information about the relationships between the various data structures, and even about underlying data storage mechanisms. A Synergy repository is a very rich source of metadata and is the primary source of metadata used by CodeGen.

It’s all about metadata! CodeGen takes information about a data structure and combines it with rules that have been defined in a template file in order to create useful code.

CodeGen Documentation

If you want to learn more then you should refer to the CodeGen documentation. If you have CodeGen installed on your Windows development system then you can access the local documentation via the command:

codegen -docs

Or you can view the documentation for the latest version of CodeGen on-line.

In the remainder of this document, we'll try to give you a very basic understanding of how CodeGen works, so that you understand what is happening when you generate code.

Record Layouts

Synergy applications define their primary data structures via record definitions. For example, a record definition for a simple CUSTOMER record might look something like this:

RECORD CUSTOMER             ; Customer record
  CUSTOMER_NUMBER    ,D6    ; Customer number                                   
  NAME               ,A30   ; Customer name                                     
  STREET             ,A25   ; Street address                                    
  CITY               ,A20   ; City                                              
  STATE              ,A2    ; State                                             
  ZIP_CODE           ,D9    ; Zip code                                          
  CONTACT            ,A25   ; Contact name                                      
  PHONE              ,D10   ; Phone number                                      
  FAX                ,D10   ; Fax number                                        
  FAVORITE_ITEM      ,D6    ; Customers favorite item                           
  PAYMENT_TERMS_CODE ,A2    ; Payment terms code                                
  TAX_ID             ,D9    ; Customers tax ID number                           
  CREDIT_LIMIT       ,D7.2  ; Credit limit                                      
ENDRECORD

The record definition defines an overall name and description for the record and goes on to define the name, data type and size of each field within the record. Comments are also used to provide a description of each field.

Repository Structures

Think of a repository STRUCTURE as a glorified record definition, it includes all of the same information as a record definition, and more. For example:

Structure CUSTOMER    DBL ISAM
   Description "Customer record"
 
Field CUSTOMER_NUMBER   Type DECIMAL   Size 6
   Description "Customer number"
   Long Description
      "SAMPLE_DATA=355232;"
   Report Just LEFT   Input Just LEFT
   Required
 
Field NAME   Type ALPHA   Size 30
   Description "Customer name"
   Long Description
      "SAMPLE_DATA=Abe's Nursery;"
   Required
 
Field STREET   Type ALPHA   Size 25
   Description "Street address"
   Long Description
      "SAMPLE_DATA=1032 Main Street;"
   Required
 
Field CITY   Type ALPHA   Size 20
   Description "City"
   Long Description
      "SAMPLE_DATA=Springfield;"
   Required
 
Field STATE   Type ALPHA   Size 2
   Description "State"
   Long Description
      "SAMPLE_DATA=MO;"
   Required
 
Field ZIP_CODE   Type DECIMAL   Size 9
   Description "Zip code"
   Long Description
      "SAMPLE_DATA=64127;"
   Report Just LEFT   Input Just LEFT
   Required
 
Field CONTACT   Type ALPHA   Size 25
   Description "Contact name"
   Long Description
      "SAMPLE_DATA=Abe Albright;"
 
Field PHONE   Template PHONE
   Description "Phone number"
   Long Description
      "SAMPLE_DATA=(555) 123-4567;"
   Required
 
Field FAX   Template PHONE
   Description "Fax number"
   Long Description
      "SAMPLE_DATA=(555) 987-6543;"
 
Field FAVORITE_ITEM   Type DECIMAL   Size 6
   Description "Customers favorite item"
   Long Description
      "SAMPLE_DATA=7;"
   Report Just LEFT   Input Just LEFT
   Required
 
Field PAYMENT_TERMS_CODE   Type ALPHA   Size 2
   Description "Payment terms code"
   Long Description
      "SAMPLE_DATA=30;"
   Required
   Selection List 0 0 0  Entries "CA", "30", "60", "90"
 
Field TAX_ID   Type DECIMAL   Size 9
   Description "Customers tax ID number"
   Long Description
      "SAMPLE_DATA=546874521;"
      "HARMONY_ROLES=Manager;"
 
Field CREDIT_LIMIT   Type DECIMAL   Size 7   Precision 2
   Description "Credit limit"
   Long Description
      "SAMPLE_DATA=5000;"
   Required
 
Key CUSTOMER_NUMBER   ACCESS   Order ASCENDING   Dups NO
   Segment FIELD   CUSTOMER_NUMBER  SegType DECIMAL
 
Key STATE   ACCESS   Order ASCENDING   Dups YES   Insert END   Modifiable YES
   Krf 001
   Description "State"
   Segment FIELD   STATE  SegType ALPHA  SegOrder ASCENDING
 
Key ZIP   ACCESS   Order ASCENDING   Dups YES   Insert END   Modifiable YES
   Krf 002
   Description "Zip code"
   Segment FIELD   ZIP_CODE  SegType DECIMAL  SegOrder ASCENDING
 
Key PAYMENT_TERMS   ACCESS   Order ASCENDING   Dups YES   Insert END
   Modifiable YES   Krf 003
   Description "Payment terms code"
   Segment FIELD   PAYMENT_TERMS_CODE  SegType ALPHA  SegOrder ASCENDING
 
Key FAVORITE_ITEM   FOREIGN
   Segment FIELD   FAVORITE_ITEM
 
Relation  2   CUSTOMERS CUSTOMER_NUMBER   ORDERS CUSTOMER_NUMBER
 
Relation  3   CUSTOMERS FAVORITE_ITEM   ITEMS ITEM_NUMBER

As you can see, each field in the STRUCTURE still contains a name, description, data type, and size, but some fields also contain additional information. Some are marked as required fields, some have selection lists of acceptable values, etc. In fact, there are over a hundred additional attributes that could be applied to each field.

You will also notice that in addition to defining the fields that make up the record, the STRUCTURE definition includes additional information such as the KEYS that can be used to access the data in various ways and the RELATIONS between this STRUCTURE and other STRUCTURES in the repository.

CodeGen can leverage all of this information, and much more when generating code that deals with these STRUCTURES.

CodeGen Template Files

Template files are text files that define some piece of generic source code. They contain a combination of actual source code and tokens that have special meaning to CodeGen. Template files have a .tpl file extension. When CodeGen processes a template file, any tokens that are encountered in the template cause it to take some action. Some tokens cause some piece of information obtained from the metadata source to be written to the output file, while other tokens cause CodeGen to perform some specific action.

Most templates are written to create output based on a source of metadata, which is usually a repository structure. Most of the useful metadata is found in repository STRUCTURE and FIELD definitions, but some tokens require you to define KEYS, TAGS, RELATIONS and FILES in the repository also. For more information, refer to Repository Setup.

If a programmer wanted to be able to generate code for Synergy external subroutines which would accept the value of the primary key for a record and then read and return the record, they might write a template like this:

<CODEGEN_FILENAME>Get<StructureName>.dbl</CODEGEN_FILENAME>
;//<CATEGORY>Synergy Subroutines</CATEGORY>
;//<DESCRIPTION>Creates a subroutine that returns a record from a file</DESCRIPTION>
;//--------------------------------------------------------
;// Template author: Jodah Veloper
;// Revision:        1.0
;// Date:            4/1/2020
;//--------------------------------------------------------
; Description: Returns a <STRUCTURE_NAME> record
; Created:     <DATE> at <TIME>

.include "<STRUCTURE_NAME>" repository, structure="str<StructureName>", end

subroutine Get<StructureName>
    <PRIMARY_KEY>
    <SEGMENT_LOOP>
    required in  a<SegmentName>, <segment_spec>
    </SEGMENT_LOOP>
    </PRIMARY_KEY>
    required out a<StructureName>, str<StructureName>

    stack record
        ch<StructureName>, int
    endrecord
proc
    <PRIMARY_KEY>
    <SEGMENT_LOOP>
    a<StructureName>.<segment_name> = a<SegmentName>
    </SEGMENT_LOOP>
    </PRIMARY_KEY>

    try
    begin
        open(ch<StructureName>=0,i:i,"<FILE_NAME>")
        read(ch<StructureName>,a<StructureName>,%keyval(ch<StructureName>,a<StructureName>,0))
    end
    catch (ex)
    begin
        clear a<StructureName>
    end
    finally
    begin
        if (ch<StructureName>&&%chopen(ch<StructureName>))
            close ch<StructureName>
    end
    endtry

    xreturn

endsubroutine

Notice that the top of the template file includes the use of a <CODEGEN_FILENAME> token, which is used to set the name of the output file based on the name of the repository STRUCTURE being used at the time.

The developer might choose to name this template file something like ReadSynergyRecord.tpl, trying to describe the type of code that the template produces; in this case a subroutine that accepts a primary key value and reads and returns the associated data record.

Generating Code

Having created the template, the developer could then process the template in conjunction with one or more repository structures, and CodeGen would create the appropriate output file(s). For example, a CodeGen command like this could be used:

codegen -t ReadSynergyRecord -s CUSTOMER -r

This command instructs CodeGen to combine template code from the file ReadSynergyRecord.tpl with repository metadata for the structure CUSTOMER, which will result in the creation of a file named GetCustomer.dbl. The -r option causes an existing file to be replaced.

Based on the definition of the CUSTOMER structure above, the resulting source file would contain the following code:

; Description: Returns a CUSTOMER record
; Created:     4/1/2020 at 11:14

.include "CUSTOMER" repository, structure="strCustomer", end

subroutine GetCustomer
    required in  aCustomerNumber, d6
    required out aCustomer, strCustomer

    stack record
        chCustomer, int
    endrecord
proc
    aCustomer.customer_number = aCustomerNumber

    try
    begin
        open(chCustomer=0,i:i,"DAT:customers.ism")
        read(chCustomer,aCustomer,%keyval(chCustomer,aCustomer,0))
    end
    catch (ex)
    begin
        clear aCustomer
    end
    finally
    begin
        if (chCustomer&&%chopen(chCustomer))
            close chCustomer
    end
    endtry

    xreturn

endsubroutine

Code Generation in Harmony Core Environments

The harmonycore and harmonydemo solution templates provide all of the files that are needed to drive the code generation environment within a Harmony Core development environment. These files are

  • Code generation batch file (regen.bat)
  • User defined tokens file (UserDefinedTokens.tkn)
  • Template files
    • Templates\*.tpl
    • Templates\SignalR\*.tpl
    • Templates\TraditionalBridge\*.tpl

All of these files are accessible from the Visual Studio Solution Explorer via the Solution Items and Templates folders.

Code Generation Batch File

This batch file contains all of the commands necessary to generate code for a Harmony Core environment. As a Harmony Core developer, you will need to edit this file to:

  1. Specify the repository STRUCTURES and FILES to be processed, and to "ALIAS" the names of structures.
  2. To determine which Harmony Core features you want your RESTful web services to implement.

We won't go into further detail here, but you will find extensive information and instructions for editing the batch file in other places in the documentation.

User-Defined Tokens File

User-defined tokens are a CodeGen concept that allows template developers to inject user-specified information into output files during code generation.

For example, you might include the user-defined token <DEVELOPER_EMAIL_ADDRESS> in a template file, and one mechanism for specifying the actual value to be used is to use a user-defined tokens file, which might contain something like this:

<DEVELOPER_EMAIL_ADDRESS>jodah.developer@gmail.com</DEVELOPER_EMAIL_ADDRESS>

Automating Code Generation in Visual Studio

It is likely that as you develop with Harmony Core you may need to generate your code on many occasions, as you add more and more data files to the REST API for example. If you wish you can execute the regen.bat file manually:

  • From the Tools menu select Comand Prompt (x64). It is important to open the command prompt in this way so that the command prompt inherits your environment settings from the Visual Studio environment.
  • In the command prompt, move up to the solution folder where regen.bat is located.
  • Execute the batch file.

If you prefer you can add a custom tool to the Visual Studio tools menu to make it easier to execute the regen.bat file. To do so:

  • From the menu select Tools > External Tools
  • Click the Add button to add a new tool
  • Set the Title to Generate Code
  • Set the Command to $(SolutionDir)regen.bat
  • set the Initial directory to $(SolutionDir)
  • Check the Use Output window option
  • Click the OK button to create the custom tool.

Having taken these steps you can now use the menu option Tools > Generate Code to execute the regen.bat file, and you will see the output from the code generator in the Output window.

Note: In recent versions of Visual Studio this mechanism has become somewhat unreliable. If you see an error message stating the RPSMFIL is not set then for some reason Visual Studio is not projecting your full environment into the process that is running your command. It sometimes helps to ensure that you have a Synergy source file open in the editor when you attempt to run the tool, but on other occasions, the automation simply fails, and you will need to run the batch file manually.


Next topic: Repository Setup


Clone this wiki locally