-
Notifications
You must be signed in to change notification settings - Fork 0
Prerequisites, Limitations and Pitfalls
The comFramework Code Generator and Excel Exporter have been implemented using Java version 23, but the JVM byte code can still be generated for the old but still frequently used Java version 8 (aka 1.8).
A Java SDK or RTE is not element of this repository but required for build or execution, respectively. The installation of an according Java system can be downloaded here https://jdk.java.net/23/ (visited Nov 2024).
The decision, which JVM byte code version is generated, is configured in the build scripts (Ant scripts) and can be easily modified. Up to now (November 2024), the offered releases have been made for JVM byte code version 8 (aka 1.8). Although quite old, this version of Java is still supported by many Java RTEs installed everywhere. Using the pre-compiled binaries without struggling with the build scripts should be possible on nearly any existing machine with an installed Java RTE.
The build is controlled by Apache Ant 1.10.15 (see http://ant.apache.org/, visited Nov 2024); if you want to change and compile the source files yourself or if you want to build the last recently committed sources then you will have to install the Java 23 SDK. Ant is element of this repository. The proper call of Ant is pre-configured in some PowerShell scripts in folder build. Before you can begin, you will need to modify one basic PowerShell script, setEnv.ps1, which prepares the environment, such that the other scripts will be able to locate the required build tools, mainly the Java compiler.
For reasons nobody will ever understand the size of the StringTemplate V4 templates is limited to 64k. Unfortunately, this is not clearly documented but appears only in a note in a sub-ordinated later manual section (see StringTemplate V4 manual, p. 52). Even worse, there seems to be no runtime check for this limit and the StringTemplate engine silently fails to generate the desired output. Instead of getting a clear error message like "Template size limit exceeded" one gets arbitrarily fragmented text output. While the limit is just hard to understand can this be considered a true bug of the engine.
The size limitation does not apply to the generated output and nor to the size of template group files but only to each distinct template.
Evidently, such large templates won't often play an important role and therefore we can live with the limitation but they are not irrelevant yet. Consider the example of an ASAM MCD-2MC file generation: One could have the idea to take his/her software project's existing *.a2l file and embed it into some template syntax like
import "lib/iterations.stg"
ASAM_MCD_2MC(cluster, info) ::= <<
<! Existing ASAM MCD-2MC file's contents go here !>
>>
and just add a small sub-template like
<iterateSignalsOfCluster(cluster,"all","both","measurement")>
in the section, where all the measurement objects belong. (measurement is an additional small template rendering a single measurement object.) The current file as a whole becomes a template.
This intuitive idea is basically valid but would fail in practice since most real ASAM MCD-2MC files exceed the 64k size limit by far. Basically, a work around would be splitting the existing file contents into numerous up-to-64k chunks, making a template each and having a sequence of references to these templates instead of the single, huge template. Needless to say, that this is an unacceptable solution.
Examples like this denote a real limitation of our code generator. In this scenario it could only generate a fragment of the aimed file, which then had to be merged with the rest using alternative techniques. (Which are however available and simple enough.)
Rendering of unknown text contents can fail because of inappropriate representation of special characters in the generated output; obviously the generation of HTML will fail if some text fragments containing the characters < or > are inserted just like that.
Inserting unknown text fragments will barely happen when writing your templates as most text output is literal text from the template or rendered Java objects of the numeric simple types. Even if Java String objects are rendered there's mostly no risk as most String objects hold hazard-free symbol names (the names of buses, frames, signals, etc.). Besides that, Java String objects are potentially dangerous. In particular the description strings (<bus.desc>, <frame.desc>, <signal.desc>, etc.), which contain the comment text from the network database files need care. The unit of a signal would be another example (<signal.unit>) where the text contents is undetermined as directly taken from the network database.
All of these strings have already been filtered for many potentially dangerous characters at parsing time. These characters have been replaced by the safe dot character (.). (Which means that the comments from the database files will be somewhat garbled in each kind of generated output.) This filtering should enable safe rendering of the text as C string in double quotes or as Octave string in single quotes. XML and HTML generation are still endangered as the characters < and > aren't filtered out. StringTemplate V4 offers a better solution: String attributes can be rendered using "XML encoding", place , e.g., <signal.unit; format="xml-encode"> into your templates for either XML or HTML output.
The StringTemplate language has a data type concept and Java objects with their classes play an important role, too, but mostly a StringTemplate template returns simple text. This ambivalence can lead to unexpected template behavior. A few examples:
-
Most of the objects in the data model can be rendered as expected by using themselves as a StringTemplate expression. The name of a PDU can, e.g., be got by simply writing <pdu>. Sometimes it's needed to have the name in all upper case characters and one could tend to write <pdu; format="upper">. Unfortunately, this fails; the output won't change. The reason is that format can be applied only to objects of type String. pdu is the Java object of type Pdu in the data model and not a String. Since the Java class has a well-defined cast operator towards Java String it can be used just like that for rendering. The upper-case problem can be solved by explicitly using Pdu's field name, which is of Java class String; <pdu.name; format="upper"> behaves as expected.
Similar for (numeric) attributes: They can be rendered just like that but if a specific printf-like number format is requested then one has to refer to their field n, like <pdu.attribMap.cycleTime.n; format="0x%04x"> as opposed to simply saying <pdu.attribMap.cycleTime>.
-
The query of an enumeration attribute yields a Boolean result, which can be used inside an if clause:
<if(pdu.attribMap.sendMode.is.regular)> /* <pdu> is a cyclically sent frame */ <endif>
The quite complex expression could tempt to place it in a sub-template, hidden somewhere in a kind of library file:
isRegular(pdu) ::= "<pdu.attribMap.sendMode.is.regular>"
and the "main" template becomes:
<if(isRegular(pdu))> /* <pdu> is a cyclically sent frame */ <endif>
This construct fails as a template (isRegular in our example) returns text, but not an object of specific data type. A sub-template is not like a sub-function in a programming language. isRegular has to render the StringTemplate expression as text and will return this text; this yields the text "true" or "false". If the main templates checks this text in its if clause then it'll always decide on true as the text "false" is neither an empty or null object nor a Boolean object with value false.
The use of Boolean expressions in StringTemplate has to be done inside a single expression in angle brackets. The result can't be stored or propagated to other templates.
-
An exception to what has been said in the previous paragraph is the dictionary. It can return either text or true Boolean values. Our samples make use of the dictionary:
isTrue ::= [ "true": true , "false": false , "": false , default: {<info.error.("isTrue got invalid argument. Check your template code")>} ]
The dictionary translates the text strings "true" and "false" into the Boolean constants true and false. (Or aborts code generation in case of unexpected other input.) The example above can be modified:
<if(isTrue.(isRegular(pdu)))> /* <pdu> is a cyclically sent frame */ <endif>
and would work as expected; isRegular returns text and isTrue translates this text into a Boolean, which can be handled by the if clause. Whether the last formulation of the problem is better (in terms of readability and maintainability) than the original remains to be seen.
Note, the dictionary translates the empty string into Boolean false. This is required since many if not most Boolean queries return null rather than false and null is rendered as empty string.