MetaGenesis MetaLX vs Apache Velocity

This post compares two template engines, MetaGenesis MetaLX and Apache Velocity.

The intent is to compare the Template Engines, not the surrounding tools and components. The surrounding tools may be mentioned when the Template Engine does not provide the feature, but the associated tooling does.

This is NOT a "which technology should I choose" post. As MetaLX is not mature enough to be publicly available, Velocity is the obvious choice. I chose to compare MetaLX and Velocity because I think Velocity shares similar goals and I respect the work done on Apache projects. This review was done for me to understand how well I did compared to a similar technology. The main differences I found can be directly linked to differences in our goals and philosophy. If I cite an advantage to MetaLX it is because it better meets my goals, which are similar, but not the same as Velocity's goals. The review of Velocity is based on reading Velocity documentation and not on using Velocity.

Note on the name MetaLX: The name is still in flux. I call the "language" MetaL for Meta Language and use the extension .mtl. I have not settled on a name for the actual template engine, in this post I will use MetaLX.

Goals

The goals and technology stack of MetaLX (Meta Language eXecutable) and Velocity are substantially the same. They are both pure Java based template engines who's goal is to provide a Model-View-Controller (MVC) architecture to allow client side and server side developers to easily work together developing web applications. They both provide an alternative approach to JSP, PHP and Perl etc. which in practice blur the line between the front and back ends.

An additional goal of MetaLX is to NOT introduce another language on the client side. The intent is to provide the needed functionality using mark-up style additions. We want front-end developers to continue to use tools of their choice, and to understand how MetaLX works in under 10 minutes.

A future goal of MetaLX is to serve multiple languages or be "language agnostic".

History

Apache Velocity started a decade or more before MetaLX and continues today as an Apache project. MetaLX has started and continues as a side project, with no public release or feedback. MetaLX was a "clean sheet" development, driven by the needs of the "main" applications I was developing at the time. It's fair to say that if I was aware of Velocity I probably would not have started MetaLX.

Having said that MetaLX is one of key technologies used in several of my complex web applications.

Overview

These technologies have both common goals and a common approach and at a macro level, remarkably similar terminology. Certainly the syntax is different, but the packages have a lot in common.

Variables, Directives, Comments and Control

Both packages share the two basic concepts of "Variables" and "Directives". MetaLX does not directly provide in-code comments and avoids code control as much as possible.

Comments:

Velocity provides: single-line, multi-line and multi-line doc comments with annotations.

MetalSrv provides: No comments.

Here are my thoughts on the subject.

  • If you want in code comments, use the comments native to the environment you are in.
  • If you are in HTML use <!-- commnent -->
  • Variables and directives are references to server-side data or operations. As such, we believe they should be documented on the server-side.
  • MetaLX directives are all "named directives" and are created in the MetaGenie CDE, which allows providing a full description for each directive. There is no reason to double document.
  • Since there is little to no "code control" provided by MetaLX, there is little client side logic that needs explaining.

Variables:

Velocity: variables start with $ and it is unclear (to me and the Velocity engine) how they end. (Example $myVar or $my1-Var) Velocity documentation goes into detail on how to use a ${myVar} format because the $myVar format does not always work and may throw an exception..

MetaLX : variables start with "$" and end with ";" (Example $myVar; or $my1-Var;) There is no need for another format, this one works.

Both MetaLX and Velocity allow variables to be set in the front end code.

  • Velocity: #set( $myVar = "myValue" )
  • MetaLX: <mg-SET:myVar="myValue"/>

Both MetaLX and Velocity allow variables to be set in the server side code.

MetaLX allows variables to be set via the url parameters: https://myDomain.com/myPage.mtl?firstName=Bob&lastName=Brown& (I use this ALL the time.)

MetaLX supports simple and structured variables:

  • simple: $myVar;
  • Hash/record: $myRecord{}; where individual elements can be accessed: $myRecord{columnName};
  • Array: $myArry[]; where individual elements can be accessed: $myArray[3];
  • Array of Hashes (aka table): $myArrayHash[]{},
    • where records can be accessed: $myArrayHash[3]{};
    • and individual elements can be accessed: $myArrayHash[3]{columnName};

MetaLX supports page, user/session, application and system variables. They are stored very differently, but accessed in a similar fashion.

  • $pageVar; They have the standard $ prefix. They only last for the life of the page.
  • $User.user{firstName}; They have a $User. prefix. These last for the user's session.
  • $App.counts{userCount}; They have a $App. prefix. These are application wide variables.
  • $Sys.serverTemperature; They have a $Sys. prefix. These are system wide variables. Typical vars are Date, Day ot the week.

MetaLX supports NESTED VAR NAMES (Mind blown!): $myArrayHash[$rowNumber;]{$columnName;};.

Here is a snippet of a REPORT that prints out specific columns of a table.

<!-- The variable $number; is automatically generated by the implied list.-->
<!--startList-->
tableName[$number;]{firstName}, tableName[$number;]{lastName}, tableName[$number;]{phone}
<!--endList-->

Null/missing var handling.

  • Velocity throws an exception.
  • MetaLX default is to remove the var and show nothing. Optionally, MetaLX can be set to show the var name (when in development) for missing data.

Directives

This is where Velocity and MetaLX take different paths.

In MetaLX the directives have a type and a name. Here are a couple of examples that cover almost all of MetaLX.

  • <mg-SET:myVar='myVarValue'>
  • <mg-QUERY:users?param1=valueOne&param2=valueTwo>
  • <mg-REPORT:userList?param1=valueOne&param2=valueTwo>
  • <mg-FORM:addUser?param1=valueOne&param2=valueTwo>
  • <mg-INCLUDE:codeFragment;/>

The set directive sets a variable, the query directive runs a query (and sets a variable). The other directive are essentially includes, for including more code. Reports, forms and includes all fetch the related code and put it in the page where the directive appeared. These can all have directives in them, a report can have a form in it and vice-versa.

They have some differences:

  • Includes are a "dynamic" includes and can target files and code fragments within the files.
  • Forms can be passed parameters and the form will be filled appropriately.
  • Reports as mentioned can have implied lists.

MetaLX reports are similar to Velocity Velocimacros ( which I will call macros) They simply bring in a chunk of HTML/JavaScript/CSS code. They support implied iterators.

Control (If, Else, For)

MetaLX has resisted providing general control features. Instead it provides "atomic" conditional assignments.

  • <mg-SET:someVar="2" if($today;=="Tuesday") default="1";/>
It also provides implied "if" and "for" in reports. Reports present information based on a table register. If the register has no data the "zero report" is presented. If the register has data, that data is presented. If the report is of type list ( they are either text or list)
<!-- Any code before the list goes here.-->
<!--startList-->
<!--This is a single row for the list code. It will be replicated for each row in the list.-->
<!--endList-->
<!-- Any code after the list elements goes here.-->

Single Page Applications

MetaLX directives can be easily wrapped in an MetaGenie JavaScript onClick event call. The directive does not change, and the resulting code is returned back to the element that called it. This makes it very simple to convert multi-page applications to single page applications.

Server side directive for a MPA:
<mg-QUERY:myQueryName?someQueryVar=$usersChoice;;REPORT:myReportName;");/>

Client side directive for a SPA:
<button onclick='MetaGenGet("QUERY:myQueryName?someQueryVar=$usersChoice;;REPORT:myReportName;");'>Request Report</button>

Example:

Velocity

#macro (writeTable $productList)
  #set ($rowCount = 1)
  #foreach($product in $productList)
    #if ($rowCount % 2 == 0)
      #set ($bgcolor = "#FFFFFF")
    #else
      #set ($bgcolor = "#CCCCCC")
  #end
  <tr>
    <td bgcolor="$bgcolor">$product.name</td>
    <td bgcolor="$bgcolor">$product.price</td>
  </tr>
    #set ($rowCount = $rowCount + 1)
    #end
  #end
<html>
  <head>
    <title>Macros Test</title>
  </head>
  <body>
    <table>
    #writeTable($products)
    </table>
  </body>
</html>

MetaLX

<!-- In the CDE there is a report called: writeTable -->
<table>
<!--startList-->
<mg-SET:bgcolor = "#FFFFFF" if($number; % 2 == 0) default="#CCCCCC";/>
  <tr>
    <td bgcolor="$bgcolor;">$product{name};</td>
    <td bgcolor="$bgcolor;">$product{price};</td>
  </tr>
<!--endList-->
</table>
<!-- last line in the report-->
<html>
  <head>
    <title>Report Test</title>
  </head>
  <body>
      <mg-REPORT:writeTable:$products[]{};;/>
  </body>
</html>

The velocity example is taken from inbravo apache-velocity-examples Test7.vm I have written a MetaLX example to match it. The differences in this example are mostly stylistic. Their are some differences that I like about MetaLX.

  • In MetaLX lists are implied with <!--startList--> and <!--endList--> and an index $number; is automatically created and incremented.
  • Not addressed in this example - what happens if there are no products? In the MetaGenie CDE when you create a report it prompts for both the "have data" report and the "no data"" report. It automatically serves the appropriate report. The "no data" report can simply be a "We have no products." The "no data" report can also be a form to add a product.
  • I have made a slight change in the MetaLX example to move <table> and </table> into the report. This is more typical of how it would be written in a production environment. Then the report can be called from any page and it will show as a whole report.
  • Atomic (single element) assignments which can include defaults and conditions is easier to understand and takes less typing.

Summary

The Velocity and MetaLX packages offer very similar functionality on the same technology stack.

This site is parked.
MetaGenesis.org an iClick.Media publication
Release A.000.001