-
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.
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.
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](Repository Setup).
For a simple example of how a repository structure can be used as a source of metadata, consider the following hypothetical structure definition:
STRUCTURE DEPARTMENT
DEPT_ID ,A10 ;Department ID (primary key)
DEPT_NAME ,A30 ;Department name
DEPT_MANAGER ,D4 ;Managers employee ID
ENDSTRUCTURE
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
; Author: <AUTHOR>
; 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
Having created the template, the developer could then process the template in conjunction with the repository structure DEPARTMENT, and CodeGen would create an output file like the one below. Notice that the template file includes a <CODEGEN_FILENAME> rule, so in this case, the name of the output file would be GetDepartment.dbl. The file would contain:
; Description: Returns a DEPARTMENT record
; Author: Jodah Veloper
; Created: 11/28/2014 at 12:00
.include "DEPARTMENT" repository, structure="strDepartment", end
subroutine GetDepartment
required in aDeptId, a10
required out aDepartment, strDepartment
stack record
chDepartment, int
endrecord
proc
aDepartment.dept_id = aDeptId
try
begin
open(chDepartment=0,i:i,"DAT:department.ism")
read(chDepartment,aDepartment,%keyval(chDepartment,aDepartment,0))
end
catch (ex)
begin
clear aDepartment
end
finally
begin
if (chDepartment&&%chopen(chDepartment))
close chDepartment
end
endtry
xreturn
endsubroutine
The harmonycore
and harmonydemo
solution templates provide two files that can be used to drive the required code generation. These files are both found in the Solution Items folder in the Visual Studio solution, and are named:
- regen.bat
- UserDefinedTokens.tkn
The solution templates also provide various CodeGen Template Files, each of which defines the basic content for each type of source file that can be used to build up a Harmony Core solution.
You will find this batch file in the main solution folder, and also you can access it in Visual Studio via the Solution Items
folder in Solution Explorer. The file is pre-configured with commands that will perform the code generation required to build out a typical Harmony Core REST APIs, based on various options that are selectable within the file.
Towards the top of the file you will see a section of code that defines several environment variables, like this:
rem ================================================================================================================================
rem Specify the names of the projects to generate code into:
set ServicesProject=Services
set ModelsProject=Services.Models
set ControllersProject=Services.Controllers
set HostProject=Services.Host
set TestProject=Services.Test
These environment variables are used to define the folders that various types of code will be generated into. The values are pre-configured to match the project folders that were provided by the project template.
Just below you will see a section of code that looks like this:
rem ==================================================================================
rem Specify the names of the repository structures to generate code from:
set DATA_STRUCTURES=
set FILE_STRUCTURES=%DATA_STRUCTURES%
rem DATA_STRUCTURES Is a list all of structures that you wish to generate models and
rem controllers for. In other words it declares all of the "entities"
rem that are being represented and exposed by the environment.
rem
rem FILE_STRUCTURES If you don't have multi-record format files then this should be the
rem same as DATA_STRUCTURES. But if you do then FILE_STRUCTURES should
rem only list ONE of the structures assigned to each file, so this list
rem will be a subset of DATA_STRUCTURES.
The DATA_STRUCTURES
environment variable is used to define which repository structures will be processed by CodeGen, and hence which source files will be produced. Simply list the named of those structures, separated by spaces, like this:
set DATA_STRUCTURES=CUSTOMERS ITEMS ORDERS ORDER_ITEMS VENDORS
In the sample environment we have implemented a mechanism that enables appropriate primary key values to be generated when new records are added via POST operations. This basically involves a “system parameters” relative file that defines data such as “next customer number” and “next order number”.
Further down in the file you will find a block of code that looks like this:
rem ================================================================================
rem Comment or uncomment the following lines to enable or disable optional features:
rem set ENABLE_GET_ALL=-define ENABLE_GET_ALL
rem set ENABLE_GET_ONE=-define ENABLE_GET_ONE
rem set ENABLE_SELF_HOST_GENERATION=YES
rem set ENABLE_CREATE_TEST_FILES=-define ENABLE_CREATE_TEST_FILES
rem set ENABLE_SWAGGER_DOCS=-define ENABLE_SWAGGER_DOCS
rem set ENABLE_POSTMAN_TESTS=YES
rem set ENABLE_ALTERNATE_KEYS=-define ENABLE_ALTERNATE_KEYS
rem set ENABLE_COUNT=-define ENABLE_COUNT
rem set ENABLE_PROPERTY_ENDPOINTS=-define ENABLE_PROPERTY_ENDPOINTS
rem set ENABLE_PROPERTY_VALUE_DOCS=-define ENABLE_PROPERTY_VALUE_DOCS
rem set ENABLE_SELECT=-define ENABLE_SELECT
rem set ENABLE_FILTER=-define ENABLE_FILTER
rem set ENABLE_ORDERBY=-define ENABLE_ORDERBY
rem set ENABLE_TOP=-define ENABLE_TOP
rem set ENABLE_SKIP=-define ENABLE_SKIP
rem set ENABLE_RELATIONS=-define ENABLE_RELATIONS
rem set ENABLE_PUT=-define ENABLE_PUT
rem set ENABLE_POST=-define ENABLE_POST
rem set ENABLE_PATCH=-define ENABLE_PATCH
rem set ENABLE_DELETE=-define ENABLE_DELETE
rem set ENABLE_SPROC=-define ENABLE_SPROC
rem set ENABLE_AUTHENTICATION=-define ENABLE_AUTHENTICATION
rem set ENABLE_FIELD_SECURITY=-define ENABLE_FIELD_SECURITY
rem set ENABLE_UNIT_TEST_GENERATION=YES
rem set ENABLE_CASE_SENSITIVE_URL=-define ENABLE_CASE_SENSITIVE_URL
rem set ENABLE_CORS=-define ENABLE_CORS
rem set ENABLE_IIS_SUPPORT=-define ENABLE_IIS_SUPPORT
rem set ENABLE_OVERLAYS=-f o
Each of these represents an option to enable a certain piece of functionality in your Harmony Core environment. Some of these options cause addiditional files to be generated, while others affect what code is generated in some of the source files.
As you can see all of the options are commented out by default, so they are not active. You can remove the rem
statement before an option in order to enable the option.
All of these options and exactly what each option is used for is discussed throughout the various pages of this documentation.
UserDefinedTokens.tkn is a CodeGen user-defined tokens file that is used to define values for several things. Thes values are inserted into various places in various generated source files.
The fact that the values are provided via user defined tokens gives you the opportunity to change the values to whatever you need to in order to build the REST API the way you want it.
The user defined tokens file looks like this:
;
; User defined tokens for the Harmony Core sample environment
;
<SERVICES_NAMESPACE>Services</SERVICES_NAMESPACE>
<MODELS_NAMESPACE>Services.Models</MODELS_NAMESPACE>
<CLIENT_MODELS_NAMESPACE>Services.Test.Models</CLIENT_MODELS_NAMESPACE>
<UNIT_TESTS_NAMESPACE>Services.Test.UnitTests</UNIT_TESTS_NAMESPACE>
;
<DATA_FOLDER>SampleData</DATA_FOLDER>
;
<API_DOCS_PATH>api-docs</API_DOCS_PATH>
<API_TITLE>Harmony Core Sample API</API_TITLE>
<API_VERSION>1.0.0</API_VERSION>
<API_DESCRIPTION>This environment presents an example of using Harmony Core to expose a collection of RESTful Web Service endpoints that allow you to interact with a small sample dataset.</API_DESCRIPTION>
<API_TERMS_URL>/license.html</API_TERMS_URL>
<API_CONTACT_EMAIL>[email protected]</API_CONTACT_EMAIL>
<API_LICENSE_NAME>BSD 2-Clause License</API_LICENSE_NAME>
<API_LICENSE_URL>https://github.com/Synergex/HarmonyCore/blob/master/LICENSE.md</API_LICENSE_URL>
<API_ENABLE_QUERY_PARAMS>(MaxExpansionDepth=4)</API_ENABLE_QUERY_PARAMS>
;
<SERVER_PROTOCOL>https</SERVER_PROTOCOL>
<SERVER_NAME>localhost</SERVER_NAME>
<SERVER_HTTP_PORT>8085</SERVER_HTTP_PORT>
<SERVER_HTTPS_PORT>8086</SERVER_HTTPS_PORT>
<SERVER_BASE_PATH>odata</SERVER_BASE_PATH>
;
<OAUTH_SERVER>http://localhost:5000</OAUTH_SERVER>
<OAUTH_API>api1</OAUTH_API>
<OAUTH_CLIENT>ro.client</OAUTH_CLIENT>
<OAUTH_SECRET>CBF7EBE6-D46E-41A7-903B-766A280616C3</OAUTH_SECRET>
<OAUTH_TEST_USER>jodah</OAUTH_TEST_USER>
<OAUTH_TEST_PASSWORD>P@ssw0rd</OAUTH_TEST_PASSWORD>
;
<ROLES_GET>Employee,Manager</ROLES_GET>
<ROLES_POST>Manager</ROLES_POST>
<ROLES_PUT>Manager</ROLES_PUT>
<ROLES_PATCH>Manager</ROLES_PATCH>
<ROLES_DELETE>Manager</ROLES_DELETE>
;
<BRIDGE_SMC_INTERFACE>SampleXfplEnv</BRIDGE_SMC_INTERFACE>
;
It is likely that as you develop 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 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
each time you need to execute the regen.bat script, and you will see the output from the code generator in the Output window.
-
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