Skip to content
This repository has been archived by the owner on May 29, 2024. It is now read-only.

Creator: HOWTO Create a Runtime Generator

Tako Schotanus edited this page Aug 14, 2019 · 13 revisions

Generators create the code for Cloud projects. That's very generic, and indeed Generators can create/contain any code you want, but the neat trick is that Generators can depend on other Generators, delegating part of often used setup tasks to them so we don't need to repeat ourselves.

So Runtime Generators are just like normal Generators, which you can read up on in this basic HOWTO Create a Generator. But this page is about Runtime Generators. What makes them different is that they are meant to serve as a basis for other Generators. Specifically they are meant to set up the base code, configuration and build files that make it possible to build and run code on a specific framework/platform.

So let's go through the steps of what it takes to create a Runtime Generator:

  1. Setup - Make sure your are set up by following the Quick Setup for Devs guide
  2. Choose a name - First we need to choose a name for our new Runtime Generator. Runtime Generators generally start with the text runtime-, so let's go with runtime-example.
  3. Create a folder - All the Runtime Generator's files need to live in a folder with the name of the Generator
$ mkdir creator/src/main/resources/META-INF/catalog/runtime-example
  1. Files - Put all the files that are required to build and run the code for your framework/platform in a subfolder called files. Here we'll show you what a basic setup for the Vert.x platform on the Java platform would look like:
generator-example/
   files/
      pom.xml
      README.md
      src/
         main/
            java/
               example/
                  RestApplication.java
            webapp/
               WEB-INF/
                  beans.xml
Show code

RestApplication.java

package example;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api")
public class RestApplication extends Application {
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>example-app</artifactId>
  <version>1.0.0</version>
  <packaging>war</packaging>
  <name>example</name>
  <description>Example application</description>
  <properties>
    <version.thorntail>2.4.0.Final</version.thorntail>
    <maven-war-plugin.version>3.2.2</maven-war-plugin.version>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.thorntail</groupId>
        <artifactId>bom</artifactId>
        <version>${version.thorntail}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.thorntail</groupId>
      <artifactId>cdi</artifactId>
    </dependency>
    <dependency>
      <groupId>io.thorntail</groupId>
      <artifactId>microprofile-health</artifactId>
    </dependency>
    <dependency>
      <groupId>io.thorntail</groupId>
      <artifactId>jaxrs-jsonp</artifactId>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>io.thorntail</groupId>
        <artifactId>thorntail-maven-plugin</artifactId>
        <version>${version.thorntail}</version>
        <executions>
          <execution>
            <goals>
              <goal>package</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <arguments>
            <argument>-S</argument>
            <argument>local</argument>
          </arguments>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>${maven-war-plugin.version}</version>
        <configuration>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

beans.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       bean-discovery-mode="annotated" version="1.1"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"/>

README.md

You will have to figure this out yourself.
Your README should probably say something about the runtime
and give instructions on how to build and run stuff.

⚠️ Of course there's already a Runtime Generator for Vert.x, it's called runtime-vertx, but this is a tutorial after all, we need to show something.

  1. Create metadata - Our Generator also needs an info.yaml in the root of our folder that contains some important metadata. For our simple example the following would be enough:
type: generator
config:
  base: language-java
  props:
    jarName: "${maven.artifactId}-${maven.version}-thorntail.jar"

There are several interestings things going on here. First we see that this Generator depends on another, that will get applied first. In this case language-java is a Generator that sets up a project's Resource Descriptors to be able to run on Kubernetes/OpenShift. We'll talk more about Language Generators later on. And secondly we see a props section that can be used to pass properties/settings to other Generators. The props section and other config elements will also be explained in more detail later on 1.

  1. Register the Generator - Finally we need to register our Generator in the GeneratorInfo list just as explained in the basic HOWTO Create a Generator.

And that's it! As you can see there isn't much to it2, creating a Runtime Generator really is just like creating any other Generator. The difference is more in the kind of files that people can expect are available. The important assumption with a Runtime Generator is that it should be reusable by other Generators.

Test your Generator

Now Generators aren't really meant to be used directly, they are the building blocks for Capabilities after all, but if you'd always have to set up a Capability just to test your work that would be a nuisance.

So to try out the effect of a single Generator you can run the following command:

$ creator apply --project testproject --name test component --generator=example-runtime

If everything works as it's supposed to, the output should look somewhat like this:

$ creator apply --project testproject --name test component --generator=example-runtime
Applied capability to 'testproject'
Go into that folder and type './gap deploy' while logged into OpenShift to create the application
in the currently active project. Afterwards type './gap push' at any time to push the current
application code to the project.

Congratulations! You just wrote your first Runtime Generator and created a project with it!

In our example we created a Runtime Generator for an already existing Language Generator, if that's all you need you are done! But what if you wanted to add support for a new language? Well to find out let's continue to HOWTO Create a Language Generator.

Further Reading

  • [1]: The Config Section - If you want to know all about the metadata mentioned in point 4
  • [2]: After adding a new Runtime - Well no, unfortunately that's not all. Read on for way too much detail on what more you need to do after you create a new Runtime.