Development Guide
In this section, practical development steps are discussed for anyone interested in contributing to the VLINGO XOOM Designer project.
Features
The XOOM Designer codebase mainly contains the implementation of the following features:
XOOM Designer
: the visual model designer itself that, besides the project generation, provides a rapid configuration for VLINGO XOOM components.XOOM CLI
: provides shortcuts for initializing XOOM Designer and interacting with Docker, Gloo Gateway API, and Kubernetes;
Although sharing the same codebase, these two features are not strongly dependent, so it's meant to be kept semantically and structurally separate. In that sense, the Designer and CLI implementations are respectively placed under the package io.vlingo.xoom.designer
and io.vlingo.xoom.cli
.
Next, the practical sections show how to maintain and expand both features.
Introduction to CLI
Once the XOOM Designer is correctly installed, the CLI is accessed from the terminal by calling the executable bash script (ex. ./xoom docker package
). Internally, this script runs the Designer
jar and passes the command, i.e. docker package
, to the CommandLineInterfaceInitializer class:
The code snippet above shows that an implementation of io.vlingo.xoom.cli.task.Task
is triggered by the user command, implying that there is one Task
subclass for each supported task. Next, the task implementation responsible for initializing the Designer service is demonstrated:
The OptionValue
class helps tasks to support execution options, which are passed along with the bash command. For instance, the designer server port can be customized as follows:
The concluding step of a Task
implementation is to edit the ComponentRegistration class mapping the task as an element of the cliTasks
list. That makes XOOM CLI able to run the task when the corresponding command is executed:
Introduction to Designer
The following diagram gives us an overview of how the Designer components interact for generating a project:
The Designer-embedded user interface illustrated above is built with Svelte. It consumes a Rest API submitting the model details to the server-side. Once successfully processed, XOOM Designer uses Apache FreeMarker for generating classes, configuration, and deployment files. That said, let's see how to add templates at the code level.
For any development on XOOM Designer you must set an environment variable named VLINGO_XOOM_STARTER_HOME
. Although you have likely already set this property in order to use the XOOM Designer, that was as an enduser, which has a different value. As a developer working on the Designer, you must set this to the absolute path of a directory relative to where the vlingo-xoom-starter
repository has been cloned.
Using a *nix shell, such as bash
, set like this:
On Windows you can use the System Properties > Advanced > Environment Variables... to set the property permanently. For a one-time setting before running the design tool you can use the command line:
After making changes, from the root project directory, build and run the Designer. On *nix run these commands:
This works on Windows:
For more details see README.md
in the xoom-designer
repository.
Model Processing Steps
While the previous section provides a quick introduction to the Designer components, this section focuses on explaining each step involved in the Designer Model processing, going through the layers, from the external to the inner, API to the full project generation.
First, let's consider how the web-based UI interacts with the Rest API when the project generation is requested:
The figure above shows the two requests submitted when the user finishes the Designer model and clicks the generate button. The first request checks if the generation path is valid by creating the full directory tree where the generated project is going to be installed. If it succeeds, the project generation is subsequently requested. The handler methods responsible for processing these requests are presented below:
ModelProcessingResource depends on ModelProcessingManager for making the generation path and generating the project. Let's get deeper into the code and see how ModelProcessingManager implements the project generation.
Reading the ModelProcessingManager code from the top, it's clear that its constructor receives a CodeGenerationStep list. The details of this ModelProcessingManager dependency are explained later, but, for now, just keep in mind that the list elements are every step responsible for creating or customizing a piece of the generated project such as configuration files, source code, and other resources.
The ModelProcessingManager.generate
is the high-level method for the project generation. It uses some auxiliary methods in order to keep the code more organized and readable. Here are the competencies of each one of these auxiliary methods:
ModelProcessingManager.validate
- checks if the submitted DesignerModel is valid. Otherwise, the project generation fails.ModelProcessingManager.mapContext
- maps a DesignerModel to CodeGenerationContext that gathers all the information required for the CodeGenerationStepsModelProcessing.processSteps
- iterates through the CodeGenerationStep list and processes the steps when theCodeGenerationStep.shouldProcess
returns true.
That said, let's have a look at the elements of the CodeGenerationStep list declared in io.vlingo.xoom.designer.Configuration
:
The steps are grouped either by the generation phase or the programming language/technology on which a specific project part is generated. The preliminary steps are responsible for preparing the internal Designer resources for a new project generation and also defining TemplateParameter values to be used in the later steps.
The core steps, declared between the preliminary and concluding steps, extend TemplateProcessingStep which is a subclass of CodeGenerationStep. This extension allows these steps to easily process Freemarker templates based on Java/React technologies.
At last, the concluding steps, like the preliminary steps, are simple CodeGenerationStep extensions that respectively perform the following tasks:
Physically create the template output processed in the core steps;
Copy necessary resources to the generated project;
Executes Maven-based Schemata goals;
Clear leftovers of the generated project from Designer internals;
The next section discusses how to implement a CodeGenerationStep and create/update code templates.
Create / Update Code Templates
The main constituent parts for every auto-generated class / project resouce are:
A Freemarker template file
A io.vlingo.xoom.codegen.template.TemplateData implementation
A io.vlingo.xoom.codegen.template.TemplateProcessingStep implementation
Considering those parts, let's take AggregateProtocol
class generation as an example and go through the implementation details, starting from the template file:
The Aggregate Protocol template file requires some parameter values to generate an Aggregate Protocol
class. The parameters handling and mapping are addressed by AggregateProtocolTemplateData as follows:
The full package name and the AggregateProtocol
class name are mapped to the template parameters in loadParameters
. Additionally, TemplateData requires the filename method implementation, which commonly uses the filename resolution logic in the corresponding TemplateStandard.
ModelGenerationStep implements the buildTemplateData
method that passes parameter values, coming from the Web-based UI, to RestResourceTemplateData. In this particular scenario, ModelTemplateDataFactory is an additional and optional class that helps building AggregateProtocolTemplateData. The shouldProcess method is also optional and useful when a TemplateProcessingStep subclass needs to be conditionally skipped.
Finally, TemplateProcessingSteps has to be added to the Configuration steps list:
Eventually, some peripheral points in the code are also involved. The following list is mainly related when a new template file is added:
1. Create an enum value in Template passing the template filename (without extension) in the constructor. Example:
2. Map the new standard file to an existing TemplateStandard or create one. Sometimes there are multiple files for the same standard. For instance, there is one Aggregate
template file for each Storage
(Journal, State Store, Object Store). That means TemplateStandard is responsible for grouping template files by standard and helps the TemplateProcessor to find the proper file based on TemplateParameters such as StorageType. The examples below demonstrate the Aggregate Protocol
and Value Object
standards.
3. In case it doesn't already exist, create an enum value in TemplateParameter for each template parameter.
To sum up, those are the common steps regarding code template files
on xoom-designer
. Our team is available to discuss and provide more information on Gitter and our public Slack workspace.
Last updated