In this blog post, I’d like to explain how the microflow engine does its job of executing complex logic in your Mendix application. First, I’ll provide a brief introduction of what microflows are and how they help you model your application, and then I’ll explain the technology behind them.
In the Mendix platform you create a model of your application using the Mendix Business Modeler. We do not generate code but interpret this model when starting the application in our server runtime. This approach has all kinds of advantages, such as being able to debug visually, even on remote environments.
To understand this article, it will help a lot if you have built microflows before but I will explain what they are as well. If you already know how to use microflows, you can skip straight to Actions.
To quote our documentation, “Microflows allow you to express the logic of your application” and “It is a visual way of expressing what traditionally ends up in textual program code”. In other words, microflows allow you to easily add complex business logic to the processes in your application without having to write code. Mendix is all about collaboration between business and IT, and microflows help a lot by giving business-minded people insight into how the application is designed.
But how does this all work? Well, let’s get into that now.
A microflow is a type of action. Actions in the server are defined by an interface that has the basic property that it can be executed. This is done by the action manager; this class is responsible for executing actions in various ways. It can execute them synchronously or asynchronously or schedule them for execution in the future, and deals with all the threading complexity.
There are various types of actions defined in the server. Some of them are for internal use, such as an action that removes expired sessions. Others can be used or even implemented by developers using Mendix. Examples are object delete or xpath query actions. If you ever created your own Java action you may have noticed that it extends
UserAction and that it must implement the method
So now we know microflows are actions that can be executed, but how do we get (instances of) this class?
Building the microflow structures
When the server starts, it will first read the file which contains your application model. The model contains all documents in your project including the microflows. The server will build structures of these microflow documents that are easier and faster to use for instantiating actual microflows than the flat model information. To give you some examples, after building these structures, a microflow that is calling another microflow will directly point at that microflow’s structure rather than an identifier in the model and the contents of a nested loop will be rendered as a separate microflow structure.
When this is done, we have a bunch of microflow structures. These represent a microflow as drawn in the modeler and contain microflow objects that represent either a start event, end event, break event or, last but not least, an activity.
These microflow objects are connected to each other by flows: the lines that connect the various blocks when you draw a microflow. A microflow object can have incoming flows and outgoing flows.
If you are experienced with microflows and are now thinking, “Hey, but what about loops or gateways?”, these are also rendered as activities. On that topic, the error event that we introduced recently can be considered a special type of end event.
As mentioned earlier, the contents of a nested loop are rendered as a microflow structure as well. For each iteration of a loop, another microflow will be instantiated. Instantiated you say? Let’s take a look…
Instantiating and running microflows
Before a certain microflow is executed, it is instantiated very quickly using the structure we built before. For a specific instance of a microflow, we need things such as the actual value of the input variables and the context of the microflow. The context contains various information including the user that is executing this microflow.
When the instance is created, the action manager executes the microflow. It will eventually run into an activity…
As I said before, some (or actually, most) microflow objects are activities. Some examples of microflow activities are changing an object, giving instructions to open a form, generating a document based on a template or importing XML.
An activity defines an
execute method. The microflow instance is passed to this method so we can do things such as look up variables that are in the scope of this microflow.
It will retrieve the context and microflow variables from the scope of the microflow, get the identifier of the XML mapping, obtain the parameter object and then decide to either export a string and return this value, or write to a file. We won’t get into the inner workings of the methods that actually do the job, but you get the idea.
Since Mendix 5, we are using OSGi as a module system. Different components can now plug their activities in the microflow engine. For example, the ‘Document Generator’ component inserts a ‘Generate document’ activity and the ‘Web UI’ component inserts activities such as ‘Show message’.
Gateways are a special kind of activity and are drawn in a different way when modelling them. A gateway represents a split in the flow of a microflow. It can be either an exclusive split or an inheritance split. An exclusive split’s default option is to parse an expression. Based on this expression, the microflow can split afterwards. The simplest case is a Boolean expression (true or false) but you could split on enumeration values as well. So how does this work? Well, we’ll have to take a look at microflow expressions.
In Mendix we have defined our own expression language. A definition that can be found on Wikipedia: “an expression in a programming language is a combination of explicit values, constants, variables, operators, and functions that are interpreted according to the particular rules of precedence and of association for a particular programming language, which computes and then produces (returns, in a stateful environment) another value. This process, like for mathematical expressions, is called evaluation. The value can be of various types, such as numerical, string, and logical.”
We wrote the grammar of the expression language in ANTLR and are also using it to generate the parser and the Abstract Syntax Trees. To quote their website, “ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files.”
You can read about the possibilities of our microflow expressions in our documentation.
Expressions can be used in various locations, to name a few: assigning a value to an attribute within a Change Object activity, in an end event when returning a variable or within an exclusive split as I mentioned earlier. Let’s take a look at an example. Say you have an application with a movie database where users can search on various properties of a movie.
The expression in this gateway is ‘Movie/Length > 180′. In the path of the microflow following the ‘true’ value you can qualify this particular movie as being long.
Sow how would an expression like this end up being evaluated?
Once the gateway action is triggered, it will give the command to evaluate the expression. This is a very simple binary expression, it will enter the binary expression class and find the operator that is used, in this case the ‘greater than’ sign. When finding this operator it will enter the method for arithmetic or comparison expressions. After getting the types of the left and right hand side of the expression and making sure the values aren’t null, it will enter the code for the relevant operator and perform the comparison. The final code is simply
value = longExpr1 > longExpr2.
What happens next is that the value is passed back to the gateway action which determines which path of the microflow to perform next. This particular movie may be marked as being long and your users that intend to stay home on a rainy evening will be able to find the perfect thing to do.
That pretty much concludes the basics of how our microflow engine operates. By using microflows, you don’t have to worry about things such as how to call a web service, how to perform an SQL query on a database with all the relevant security constraints or how to open a form on the client. The microflow engine provides these functions in the form of simple activities you can add to your application.
I hope you enjoyed this insight. Please leave a comment if there’s anything you’d like to point out or ask.