Skip to content

Latest commit

 

History

History
160 lines (114 loc) · 10.6 KB

DEV-GUIDE.md

File metadata and controls

160 lines (114 loc) · 10.6 KB

Development Guide

In this section, practical development steps are discussed for anyone interested in contributing to xoom-designer.

Introduction to Application Generation feature

The following diagram gives us an Application Generation overview showing the interaction of its components:

As illustrated above, Application Generation can be run by two commands: xoom gen or xoom gui. Both are alternative ways for a quick start with VLINGO XOOM, having exactly the same parameters list. The only difference is that the latter reads parameters from a properties file, while the first consumes parameters from a web-based UI.

The second half of the diagram shows some tools that perform core actions. Maven Archetypes creates the project structure, dynamically organizing the directory hierarchy, Maven configuration, also handling deployment resources as Dockerfile and K8s manifest file. Further, Apache FreeMarker takes care of classes generation by processing preexisting code templates. That said, let's see how to add templates at code level.

Create / Update Code Templates

The main constituent parts for every auto-generated class are:

Considering those parts, let's take RestResource class generation as an example and go through the implementation details, starting from the template file:

package ${packageName};

import io.vlingo.xoom.http.resource.Resource;
import static io.vlingo.xoom.http.resource.ResourceBuilder.resource;

public class ${resourceName}  {

    public Resource<?> routes() {
        return resource("${resourceName}" /*Add Request Handlers here as a second parameter*/);
    }

}

As easy as it seems, the Rest Resource template file requires only two parameters values to generate a Rest Resource class: packageName and resourceName. The parameters handling and mapping are addressed by RestResourceTemplateData as follows:

public class RestResourceTemplateData extends TemplateData {

    private final static String PACKAGE_PATTERN = "%s.%s";
    private final static String PARENT_PACKAGE_NAME = "resource";

    private final String packageName;
    private final String aggregateName;
    private final TemplateParameters parameters;

    public RestResourceTemplateData(final String aggregateName,
                                    final String basePackage) {
        this.aggregateName = aggregateName;
        this.packageName = resolvePackage(basePackage);
        this.parameters = loadParameters();
    }

    private TemplateParameters loadParameters() {
        return TemplateParameters
                .with(REST_RESOURCE_NAME, REST_RESOURCE.resolveClassname(aggregateName))
                .and(PACKAGE_NAME, packageName);
    }

    private String resolvePackage(final String basePackage) {
        return String.format(PACKAGE_PATTERN, basePackage, PARENT_PACKAGE_NAME).toLowerCase();
    }

    @Override
    public TemplateStandard standard() {
        return REST_RESOURCE;
    }

    @Override
    public TemplateParameters parameters() {
        return parameters;
    }

    @Override
    public String filename() {
        return standard().resolveFilename(aggregateName, parameters);
    }

}

RestResource classes should be placed under its own package. Hence, the resolvePackage method appends the project base package to the resource package. The full package name and the RestResource 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.

public class RestResourceGenerationStep extends TemplateProcessingStep {

    @Override
    protected List<TemplateData> buildTemplateData(final TaskExecutionContext context) {
        final String projectPath = context.projectPath();
        final String basePackage = context.propertyOf(Property.PACKAGE);
        final String restResourcesData = context.propertyOf(Property.REST_RESOURCES);
        return RestResourceTemplateDataFactory.build(basePackage, projectPath, restResourcesData);
    }

    @Override
    public boolean shouldProcess(final TaskExecutionContext context) {
        return context.hasProperty(Property.REST_RESOURCES);
    }

}

RestResourceGenerationStep implements buildTemplateData method that passes parameter values, coming from the Web-based UI or properties file, to RestResourceTemplateData. In this particular scenario, RestResourceTemplateDataFactory is an additional and optional class that helps building RestResourceTemplateData. The shouldProcess method is also optional and useful when a TemplateProcessingStep subclass needs to be conditionally skipped.

Finally, TemplateProcessingStep has to be added in the Configuration steps list:


    public static final List CODE_GENERATION_STEPS = Arrays.asList(
            new ModelGenerationStep(),
            new ProjectionGenerationStep(),
            new StorageGenerationStep(),
            new RestResourceGenerationStep(),
            new BootstrapGenerationStep(),
            new ContentCreationStep()
    );

Eventually, some peripheral points in the code are also involved. The following list is mainly related to a template file creation:

  1. Create an enum value in Template passing the template filename (without extension) in the constructor. Example:

    public enum Template {

        //Other template filenames

        REST_RESOURCE("RestResource")

        //Enum attributes
    }

  1. 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 example below demonstrates the Aggregate and Rest Resource standards. The latter has only one related template file:

    public enum TemplateStandard {
        
        AGGREGATE(parameters -> AGGREGATE_TEMPLATES.get(parameters.from(STORAGE_TYPE))),
        REST_RESOURCE(parameters -> CodeTemplateFile.REST_RESOURCE.filename),

        //Other standards
    }

  1. In case it doesn't already exist, create an enum value in TemplateParameter for each template parameter.

In sum, those are the common steps regarding code template files on xoom-designer. Our team is available to discuss and provide more information on Gitter.