This is a simple project that I did in JetBrains MPS. Since I very much like working with MPS, I’ve written this blog post to document it. I hope that it may find it useful if you’re starting with MPS.
I have tried to include as many illustrations as possible.
Motivation
While developing 2D algorithms, I found the debugging to be a real pain. It’s easier to see a curve on a display than to make sense from a (lengthy) set of coordinates.
Requirements
Functional requirements
A set of methods, constructed from the primitive commands that the display offers, eg. “drawPath”, “clearDisplay”.
Quality requirements
To be able to draw curves while in the debugger. The display needs to be updated even if the application under test is stopped.
Communication only needs to be one way: From the application under test to the display.
The number of calls to the draw method will be small. Therefore performance is not an issue.
Solution
Create a stand-alone process with a JSVG canvas. This will guarantee that the display will be updated even if the application under test is stopped.
Use HTTP to connect the application under test to the display. This is simple to write and simple to test (e.g. via a web browser). The connection can be established “on demand”.
Solution design

The client issues remote commands, sends them via HTTP to the server, where they are translated into draw commands. The remote commands and the corresponding command handlers would be defined using a DSL.
If you open the following URL in your browser
http://localhost:8000/draw?message%3DHello%20World%21%26path%3DM%20100%2C100%20L%20100%2C200%20200%2C200%20200%2C%20100%20z%26style%3Dfill%3Anone%3Bstroke%3A%23000000
the server will display this image:

To generate the query, I’ve used a simple online tool to URL-encode the parameters.
The development process in detail
Step 1: Hand-writing a prototype solution

A prototype client and server were written by hand, using an IDE.
Step 2: Creating the concepts in MPS

Step 3: Transferring the JAR files to MPS

The code generated by MPS would refer to classes and methods from the hand-written solution. Therefore JAR files, containing this part of the prototype application need to be imported into MPS.
Step 4: Creating templates in MPS

Now that the classes and methods are available in MPS, the templates are created. The hand-written code is used as a basis for this step.
Step 5: Creating the model



In the definition of this command a global constant, styleBlue, is referenced.

In the definition of this command a local constant, styleGreen, is defined and referenced.
Step 6: Generating the source code

Client Business Logic (generated)
The following code is generated for the three client commands shown above. The code uses an abstraction layer QueryGenerator to specify the URI, add parameters and execute the query.

Server Business Logic (generated)
The first block defines the global constants and registers the Request Handler classes.



Implementation details
Structure aspect


I have introduced the Interface StringValueTraits. The scope of StringParameters makes them unique, if they are unique for the ClientMethod. StringConstants, on the other hand, can clash between different instances of CommandListVersion. Therefore the version of the CommandListVersion is appended to the declarationName.
References and reference constraints
I want to define (client) methods with (string) parameters. In these method definitions I want to call draw methods and provide these method calls with values. A value may be
- a parameter of the method that I am declaring
- a constant, that I defined within the method declaration, or
- a global constant.
Here I found the calculator example from the MPS Advanced Online Course rather helpful.
The following diagram shows the possible reference targets from a StringValueReference within a ServerCommand.

In the first attempt, I implemented the scope handler in StringValueReference.

This handler looks for its ancestor of type ClientCommand and collects all StringConstant instances from commandConstants and all StringParameter instances from commandParameters. It then looks for its ancestor of type CommandListVersion and collects all StringConstant instances.

In the next attempt, I went for inherited scope and implemented getScope() in ClientCommand and in CommandListVersion.


The chain of ScopeProviders looks like this:

Editor aspect
As the language is very straightforward, so I will not show the editors here.
Checking Rules
I use Checking Rules to validate the model on the fly:
- Does the name follow the rules for a valid identifier?
- Are the names unique?
- Are version numbers unique?
- Are all parameters and constants referenced?

Generator aspect
The generator consists of nested loops. A SWITCH macro is used to generate the code for the difference ServerCommands.


Within the property / reference macros behavior methods are used, to keep the templates free from application logic.


The method commandHandlerClassname() will only generate a version identifier if there are more than one CommandListVersion.
Lessons Learned
Isolate the generator from the implementation
- The client and server application are based on the HTTP protocol.
- To get the Proof of Concept up and running as fast as possible, I imported the full JDK into MPS, since the generated code relied on java.net classes. But: Importing the JDK “pollutes” the model.
- For version 2 I created an abstraction layer that consists mostly of interfaces and that contains no dependencies on the JDK. By using the factory pattern, dependencies on the handwritten code for client and server were eliminated.

Downloads
The projects are available on GitHub, if you would like to take a deep dive.
The MPS project RemoteAdapterGenerator
The Maven project remote canvas
The Maven project contains three parts:
- svghttpd: A swing application with an SVG canvas and an attached HTTP server
- svgclient: A client library to issue drawing commands to the swing application via HTTP
- svgdemo: A demo application that shows how to use the client library
To build and run the swing application:
- mvn clean compile assembly:single
- java -jar target\svghttpd-1.0-jar-with-dependencies.jar
This project also creates the two interface JAR files that are used in RemoteAdapterGenerator:
- svgclient-1.0-interface.jar
- svghttpd-1.0-interface.jar
References
Here are resources that I found helpful:
Gabriele Tomassetti: How to Add JARs to a Jetbrains MPS Project – Strumenta (tomassetti.me)