7.6 Customizing Code Generation
An outstanding feature of AgenPro is its flexibility. The complete code generation process can be customized which allows to write code generation from SNMP MIB specifications for virtually any programming language and SNMP agent or manager API.
AgenPro's code generation templates are based on VTL, the Velocity Template Language from Apache. Also VTL, in the first place, is designed for generating text or HTML output with dynamic content, its clear differentiation between model, view, and controller (MVC) makes it also a first choice for code generation.
The control structures provided by VTL are limited, but they also make it easy for users with little or no programming experience to write scripts based on VTL. Supported control statements are #if..#else..#end to conditionally execute statements and #foreach..#end to execute statements for each element of a given list. With the #macro statement parts of script that are frequently used can be combined into a function that can be called in the template by #<macro_name>. Please refer to the VTL user guide or the VTL reference for a complete description of the VTL language.
An AgenPro template differs from any other Velocity Macro (VM) only by the model AgenPro provides for the template. The Model is accessed from a VM through contexts.
AgenPro offers three kinds of code generation jobs that provide different sets of contexts:
1. jobs that are run once per code generation
2. jobs that are run once per MIB module
3. jobs that are run once per each context generated by a .
For most use cases, the first two job types are sufficient and provide the best performance. However if you need full flexibility, the third type would be the best choice. The first two types are used by the standard AGENT++ code generation projects whereas the third is used by the more advanced example project that selects the MIB objects to generate by a VTL template and generates each table and each scalar and notification object in its own set of source files. The SNMP4J-Agent default templates also use a context selection template.
The contexts supported by the three job types are listed in the below table and grouped as follows:
1. The first group of Velocity contexts provide utility functions and services that are independent from the chosen job generation type.
2. The second group of Velocity contexts provide access to objects available in the job's current file context. When running a job of type "", then there might by more than one file context per job execution. In any other case, these Velocity contexts of this group will not change during the execution of the job.
3. The third and last group of Velocity contexts provide access to the MIB modules and module names that were selected in step three of the code generation wizard. When executing a job of type "" the content of these Velocity contexts remain the same, regardless for which file contexts code generation templates are executed. To get the MIB modules selected by a selection template for a particular file context, use the contextModules and contextModuleNames Velocity contexts.
|
Context |
Class |
Job |
Description |
|---|---|---|---|
|
existingCode |
Map |
all |
The existingCode context contains the protected code snippets collected from the input file, if an input directory had been specified. Otherwise, the Hashtable is empty. The key for the Hashtable entries is built using the form: <class>[::<method>]. |
|
agenUtils |
AgenUtils |
all |
The agenUtils context provides various utility functions supporting the analysis of MIB content. For example, retrieving MIB objects by name and getting the effective syntax of an OBJECT TYPE. |
|
agenStringUtils |
AgenStringUtils |
all |
The agenStringUtils context provides string utility functions to search and replace strings using regular expressions. |
|
stringUtils |
StringUtils |
all |
Additional string utilities provided by Velocity, for example reading a file into a String object. |
|
agentCapabilities |
IAgentCapabilities |
all |
This context is only available if a AGENT-CAPABILITIES statement has been selected for this project in the corresponding project wizard. It provides access to the selected statement's SMI definition. |
|
module |
IModule |
2,3* |
The module context provides access to the target MIB module of this code generation job. |
|
moduleName |
String |
2,3* |
The name of the target MIB module (e.g. SNMPv2-MIB). |
|
moduleNameNoHyphen |
String |
2,3* |
The name of the target MIB with hyphen "-" replaced by underscores "_" (e.g. SNMPv2_MIB). |
|
context |
String |
2,3 |
The context name string generated by the selection template. This can be any string that must not contain ";", ",", and "=" characters. In case of jobs of type 2, the context name string equals the moduleName. |
|
contextNoHyphen |
String |
2,3 |
The context name string generated by the selection template where hyphen characters ("-") are replaced by underscores ("_"). |
|
contextModules |
List |
2,3 |
The contextModules Velocity context provides access to all IModule instances selected for the current file context. In case of a job of type "", the contents of this Velocity context is the same as modules. |
|
contextModuleNames |
List |
2,3 |
The contextModules Velocity context provides access to all MIB module names selected for the current file context. In case of a job of type "", the contents of this Velocity context is the same as moduleNames. |
|
contextObjects |
List |
3 |
The contextObjects Velocity context provides access to all IObject instances selected for the current file context. |
|
scalars |
List |
2,3 |
The scalars context provides access to all scalar OBJECT-TYPE definitions of module. |
|
tables |
List |
2,3 |
The tables context provides access to all table objects defined in module. Table objects are those OBJECT-TYPE definitions that have an INDEX clause. The objects are ordered by their object identifier (OID) |
|
tablesByDependencies |
List |
2,3 |
The tablesByDependencies context provides access to the same table objects as the context tables, but in different order. Tables with an INDEX clause „AUGMENTS“ will succeed tables which those tables depend on. Thr remaining tables are sorted by their object identifier (OID). |
|
columns |
Map |
2,3 |
The columns context provides access to all columnar OBJECT-TYPE definitions. The keys of the Map are the table objects in the table context Vector. By calling the get method of the columns Map all columnar objects of the corresponding table are returned as a List of IObjectType instances. |
|
indexes |
Map |
2,3 |
The indexes context provides access to the index objects of table objects. The keys of the Map are the table objects in the table context List. By calling the get method of the columns Map all index objects of the corresponding table are returned as a List of IObjectType instances. |
|
notifications |
List |
2,3 |
The notifications context provides access to all trap and notification objects defined in module. Notifications are TRAP-TYPE (SMIv1) or NOTIFICATION-TYPE (SMIv2) definitions. |
|
identities |
List |
2,3 |
The identities context provides access to all OBJECT-IDENTITY definitions defined in module. This list is empty for SMIv1 MIB modules. |
|
String |
all† |
The output (file name) generated by the file name generation template. Consequently, this context is not available in the file name generation template itself. |
|
|
String |
all† |
Same as above but dots "." in the filename are replaced by underscores "_". |
|
|
List |
3 |
All contexts generated by the selection template. For each of the context string in this vector there will be an output file generated. To get the index of the current context within a code generation template, the $contexts.indexOf($context) method can be used. |
|
|
List |
1,3 |
The modules context provides access to all MIB modules (IModule instances) for that program code should be generated. |
|
|
List |
1,3 |
The moduleNames context provides access to all MIB module names (String instances) of the target modules. |
|
*Although these contexts are available in jobs of type 3, its use is not recommended because the MIB module referenced is the first MIB module that occurs in the generated contexts. Any other MIB modules used in the context will be hidden by these contexts. Instead of using such a context, the $agenUtils.getModule(IObject) method should be used to determine the MIB module for a MIB object. †These contexts are not available in code generation templates. |
Since AgenPro 4.1 the following type of comments are supported:
|
Comment Start/End |
Tag |
Example |
|---|---|---|
|
// |
|:AgenPro|= |
//|:AgenPro|=_helloWorld String msg = "Hello World"; //|AgenPro:| |
|
// |
--AgentGen BEGIN= |
//--AgentGen BEGIN=_helloWorld String msg = "Hello World"; //--AgentGen END |
|
/* */ |
|:AgenPro|= |
/*|:AgenPro|=_helloWorld*/ String msg = "Hello World"; /*|AgenPro:|*/ |
|
<!-- --> |
|:AgenPro|= |
<!--|:AgenPro|=pom.xml-->#if ($existingCode.get("pom.xml")) $existingCode.get("pom.xml") #else <project></project> #end <!--|AgenPro:|--> |
|
#-- --# |
|:AgenPro|= |
#--|:AgenPro|=agen.properties--# #if ($existingCode. $existingCode.get("agen.properties") #else snmp4j.agent.cfg.contexts= #end #--|AgenPro:|--# |
The Tags containing the character sequence AgentGen are still supported but should not be used for new development.
The tags starting with a // comment do not have an end comment. Instead, the line end terminates the string after the equal sign of the tag. That string following the start tag, is used as key for the parsed code between the tags. The key must be unique per source (input) file.