-
Notifications
You must be signed in to change notification settings - Fork 53
Creator: HOWTO Create a Generator
Generators create the code for Cloud projects. In their simplest form they just have a set of template files that get copied to a project under construction. They can also make changes to already existing files. Among the more advanced features is the creation of Resource Descriptors for deployment on Kubernetes/OpenShift.
So let's go through the steps of what it takes to create a Generator:
- Setup - Make sure your are set up by following the Quick Setup for Devs guide
-
Choose a name - First we need to choose a name for our new Generator. Let's go with
generator-example
. - Create a folder - All the Generator's files need to live in a folder with the name of the Generator
$ mkdir creator/src/main/resources/META-INF/catalog/generators/generator-example
-
Files - Put any files that you want copied in a subfolder called
files
. Imagine the following folder structure for a very simple Java application:
generator-example/
files/
src/
main/
java/
example/
GreetingEndpoint.java
Greeting.java
merge/
pom.xml
Show code
GreetingEndpoint.java
package example;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
@Path("/")
@ApplicationScoped
public class GreetingEndpoint {
private static final String template = "Hello, %s!";
@GET
@Path("/greeting")
@Produces("application/json")
public Greeting greeting(@QueryParam("name") String name) {
String suffix = name != null ? name : "World";
return new Greeting(String.format(template, suffix));
}
}
Greeting.java
package io.openshift.booster.http;
public class Greeting {
private final String content;
public Greeting() {
this.content = null;
}
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
pom.xml
<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">
<properties>
<version.resteasy>3.0.24.Final</version.resteasy>
<version.restassured>3.0.7</version.restassured>
<version.assertj>3.8.0</version.assertj>
<version.awaitility>3.1.0</version.awaitility>
</properties>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>io.thorntail</groupId>
<artifactId>jaxrs-jsonp</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${version.resteasy}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${version.restassured}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${version.awaitility}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${version.assertj}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>${version.resteasy}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Another thing you might have noticed is that pom.xml
file in the merge
directory instead of the among the files
. And if you looked at the actual XML provided as an example you might even have noticed the POM file doesn't seem complete! What's up with that? Good question!
So the thing is that, as you'll learn later on, a POM file will already be provided for us. The only thing that we want is to be able to add new things to it, things like dependencies and properties that are needed by the code this Generator is adding.
So that's why the POM file is not in the files
directory, but in merge
: we don't want it copied, possibly overwriting any existing POM files, we want it merged with the provided POM file.
-
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: "runtime-vertx
The interesting part here is the "base": "runtime-vertx"
1 which tells the Creator that before applying this Generator it should actually first apply the Runtime Generator named runtime-vertx
. If you were wondering before why there seemed so little code in our example, it's because we can delegate certain tasks to other Generators. In this case runtime-vertx
is a Generator that sets up a project to use the Vert.x framework. It will provide us with all the basic necessary to build and run our code. We'll talk more about Runtime Generators later on.
- Register the Generator - Finally we need to register our Generator in the GeneratorInfo list. Just add a item to the end of the list with the exact same name we gave our Generator in the first step. It would look something like this:
enum class GeneratorInfo(val klazz: GeneratorConstructor) {
`database-crud-dotnet`,
`database-crud-nodejs`,
`database-crud-quarkus`,
.
.
.
`rest-dotnet`,
`rest-nodejs`,
`rest-quarkus`,
`rest-springboot`,
`rest-thorntail`,
`rest-vertx`,
`rest-wildfly`,
`example-generator`;
That's it! That's all there is to creating a simple 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 ittest component --generator=example-generator
If everything works as it's supposed to, which it never does of course the first time, but when it does the output should look somewhat like this:
$ creator apply --project testproject --name ittest component --generator=example-generator
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 Generator and created a project with it!
When you're done celebrating, let's continue to HOWTO Create a Runtime Generator
- [1]: The Config Section - If you want to know all about the metadata mentioned in point 4
- Create a Custom Generator - What if you need total control over your Generator? Read on.