-
Notifications
You must be signed in to change notification settings - Fork 14
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.
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.
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.
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.
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.
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.
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
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.
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:
- Specify the repository STRUCTURES and FILES to be processed, and to "ALIAS" the names of structures.
- 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 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>[email protected]</DEVELOPER_EMAIL_ADDRESS>
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 selectComand 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
toGenerate Code
- Set the
Command
to$(SolutionDir)regen.bat
- set the
Initial directory
to$(SolutionDir)
-
Check
theUse 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.
-
Tutorial 2: Building a Service from Scratch
- Creating a Basic Solution
- Enabling OData Support
- Configuring Self Hosting
- Entity Collection Endpoints
- API Documentation
- Single Entity Endpoints
- OData Query Support
- Alternate Key Endpoints
- Expanding Relations
- Postman Tests
- Supporting CRUD Operations
- Adding a Primary Key Factory
- Adding Create Endpoints
- Adding Upsert Endpoints
- Adding Patch Endpoints
- Adding Delete Endpoints
-
Harmony Core Code Generator
-
OData Aware Tools
-
Advanced Topics
- CLI Tool Customization
- Adapters
- API Versioning
- Authentication
- Authorization
- Collection Counts
- Customization File
- Custom Field Types
- Custom File Specs
- Custom Properties
- Customizing Generated Code
- Deploying to Linux
- Dynamic Call Protocol
- Environment Variables
- Field Security
- File I/O
- Improving AppSettings Processing
- Logging
- Optimistic Concurrency
- Multi-Tenancy
- Publishing in IIS
- Repeatable Unit Tests
- Stored Procedure Routing
- Suppressing OData Metadata
- Traditional Bridge
- Unit Testing
- EF Core Optimization
- Updating a Harmony Core Solution
- Updating to 3.1.90
- Creating a new Release
-
Background Information