Skip to content

Commit

Permalink
Generate events using jsonschema2pojo and mustache template (#58)
Browse files Browse the repository at this point in the history
Initial changes to generate events using jsonschema2pojo and mustache template, 
/src/main/resources/template/event-template.mustache

pom.xml has the plugin to generate jsonschema2pojo and plugin to run the main
class from CDEventsGenerator to create events using mustache template.

Running ./mvnw verify

Generates models using jsonschema2pojo for each event under - dev.cdevents.models.generated.subject.predicate
Generates events from mustache template and placed under - dev.cdevents.events.generated

Note:

Generating only 3 events for an initial review and schema files for the same are placed under - /src/main/resources/schema (This will essentially point to spec repo to generate all the events once reviewed)
Removed current Events(dev.cdevents.events) and Models(dev.cdevents.models) that are manually created earlier.

---------

Signed-off-by: Jalander Ramagiri <[email protected]>
Co-authored-by: Lapenta Francesco Davide <[email protected]>
  • Loading branch information
rjalander and lapentad authored Oct 2, 2023
1 parent d6e4167 commit 739fb09
Show file tree
Hide file tree
Showing 109 changed files with 3,492 additions and 10,066 deletions.
8 changes: 6 additions & 2 deletions .github/linters/sun_checks.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@

<!-- Checks for imports -->
<!-- See https://checkstyle.org/config_imports.html -->
<module name="AvoidStarImport"/>
<module name="AvoidStarImport">
<property name="allowClassImports" value="true"/>
</module>
<module name="IllegalImport"/>
<!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
Expand Down Expand Up @@ -171,7 +173,9 @@
</module>
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<module name="MagicNumber"/>
<module name="MagicNumber">
<property name="ignoreFieldDeclaration" value="true"/>
</module>
<module name="MissingSwitchDefault"/>
<module name="MultipleVariableDeclarations"/>
<module name="SimplifyBooleanExpression"/>
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
- name: Lint Code Base
uses: github/super-linter/slim@v4
env:
FILTER_REGEX_INCLUDE: .*src/main/.*
FILTER_REGEX_INCLUDE: .*sdk/src/main/.*|.*generator/src/main/.*
VALIDATE_ALL_CODEBASE: false
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# mvnw is provided as is from the Maven Wrapper project. Can't change it
FILTER_REGEX_EXCLUDE: .*mvnw
FILTER_REGEX_EXCLUDE: .*mvnw|.*sdk/src/main/java/dev/cdevents/models/.*
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
- name: Release
run: |
./mvnw -ntp -B --file pom.xml -Prelease
./mvnw -ntp -B --file pom.xml -Prelease -pl :cdevents-sdk-java-parent
env:
JRELEASER_GITHUB_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
JRELEASER_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
Expand Down
147 changes: 147 additions & 0 deletions generator/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?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>

<parent>
<groupId>dev.cdevents</groupId>
<artifactId>cdevents-sdk-java-parent</artifactId>
<version>0.1.3-SNAPSHOT</version>
</parent>

<artifactId>cdevents-sdk-java-generator</artifactId>

<name>cdevents-sdk-java-generator</name>
<description>Source code generator for CDEvents Java SDK</description>
<url>https://github.com/cdevents</url>

<properties>
<maven.javadoc.skip>true</maven.javadoc.skip>
<maven.source.skip>true</maven.source.skip>
<maven.deploy.skip>true</maven.deploy.skip>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<sdk.project.dir>${project.basedir}/../sdk</sdk.project.dir>
</properties>

<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>

<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.6</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.jsonschema2pojo</groupId>
<artifactId>jsonschema2pojo-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<outputDirectory>${sdk.project.dir}/src/main/java</outputDirectory>
<includeHashcodeAndEquals>false</includeHashcodeAndEquals>
<includeToString>false</includeToString>
<addCompileSourceRoot>false</addCompileSourceRoot>
</configuration>
<executions>
<execution>
<id>generate-artifact-packaged-from-schema</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<sourcePaths>
<sourcePath>${sdk.project.dir}/src/main/resources/schema/artifact-packaged-event.json
</sourcePath>
</sourcePaths>
<targetPackage>dev.cdevents.models.artifact.packaged</targetPackage>
</configuration>
</execution>
<execution>
<id>generate-artifact-published-from-schema</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<sourcePaths>
<sourcePath>${sdk.project.dir}/src/main/resources/schema/artifact-published-event.json
</sourcePath>
</sourcePaths>
<targetPackage>dev.cdevents.models.artifact.published</targetPackage>
</configuration>
</execution>
<execution>
<id>generate-pipeline-run-finished-from-schema</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<sourcePaths>
<sourcePath>
${sdk.project.dir}/src/main/resources/schema/pipeline-run-finished-event.json
</sourcePath>
</sourcePaths>
<targetPackage>dev.cdevents.models.pipelinerun.finished</targetPackage>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>run-CDEventsGenerator-main-class</id>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>dev.cdevents.generator.CDEventsGenerator</mainClass>
<arguments>
<argument>${project.basedir}</argument>
<argument>${sdk.project.dir}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
165 changes: 165 additions & 0 deletions generator/src/main/java/dev/cdevents/generator/CDEventsGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package dev.cdevents.generator;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public final class CDEventsGenerator {

private CDEventsGenerator() {
}

private static ObjectMapper objectMapper = new ObjectMapper();
private static Logger log = LoggerFactory.getLogger(CDEventsGenerator.class);

private static final int SUBJECT_INDEX = 2;
private static final int PREDICATE_INDEX = 3;
private static final int VERSION_INDEX = 4;
private static final int SUBSTRING_PIPELINE_INDEX = 8;

private static final String TARGET_PACKAGE = "src/main/java/dev/cdevents/events";

/**
* Event JsonSchema files location.
*/
private static final String RESOURCES_DIR = "src/main/resources/";
/**
* Mustache generic event template file.
*/
private static final String EVENT_TEMPLATE_MUSTACHE = RESOURCES_DIR + "template/event-template.mustache";

/**
* Main method to generate CDEvents from Json schema files.
* @param args [0] - base directory for the cdevents-java-sdk-generator module
* [1] - base directory for the cdevents-java-sdk module
*/
public static void main(String[] args) {
if (args == null || args.length < 2) {
throw new IllegalArgumentException("Insufficient arguments passed to CDEventsGenerator");
}
String generatorBaseDir = args[0];
String sdkBaseDir = args[1];
String targetPackageDir = sdkBaseDir + File.separator + "src/main/java/dev/cdevents/events";
File folder = new File(sdkBaseDir + File.separator + RESOURCES_DIR + "schema");
System.out.println(folder.toPath().toAbsolutePath());
if (folder.isDirectory()) {
File[] files = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".json"));
if (files != null) {
//Create Mustache factory and compile event-template.mustache template
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(generatorBaseDir + File.separator + EVENT_TEMPLATE_MUSTACHE);

//Generate a class file for each Json schema file using a mustache template

for (File file : files) {
SchemaData schemaData = buildCDEventDataFromJsonSchema(file);
generateClassFileFromSchemaData(mustache, schemaData, targetPackageDir);
}
}
}
}

private static void generateClassFileFromSchemaData(Mustache mustache, SchemaData schemaData, String targetPackageDir) {
String classFileName = StringUtils.join(new String[]{schemaData.getCapitalizedSubject(), schemaData.getCapitalizedPredicate(), "CDEvent", ".java"});
File classFile = new File(targetPackageDir, classFileName);
try {
FileWriter fileWriter = new FileWriter(classFile);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
mustache.execute(bufferedWriter, schemaData).flush();
fileWriter.close();
} catch (IOException e) {
log.error("Exception occurred while generating class file from Json schema {}", e.getMessage());
throw new IllegalStateException("Exception occurred while generating class file from Json schema ", e);
}
log.info("Rendered event-template has been written to file - {}", classFile.getAbsolutePath());
}

private static SchemaData buildCDEventDataFromJsonSchema(File file) {
SchemaData schemaData = new SchemaData();

log.info("Processing event JsonSchema file: {}", file.getAbsolutePath());
try {
JsonNode rootNode = objectMapper.readTree(file);
JsonNode contextNode = rootNode.get("properties").get("context").get("properties");

String eventType = contextNode.get("type").get("enum").get(0).asText();
log.info("eventType: {}", eventType);
String[] type = eventType.split("\\.");
String subject = type[SUBJECT_INDEX];
String predicate = type[PREDICATE_INDEX];
String capitalizedSubject = StringUtils.capitalize(subject);
if (subject.equals("pipelinerun")) {
capitalizedSubject = capitalizedSubject.substring(0, SUBSTRING_PIPELINE_INDEX)
+ StringUtils.capitalize(subject.substring(SUBSTRING_PIPELINE_INDEX));
}
String capitalizedPredicate = StringUtils.capitalize(predicate);
String version = type[VERSION_INDEX];

//set the Schema JsonNode required values to schemaData
schemaData.setSubject(subject);
schemaData.setPredicate(predicate);
schemaData.setCapitalizedSubject(capitalizedSubject);
schemaData.setCapitalizedPredicate(capitalizedPredicate);
schemaData.setSchemaFileName(file.getName());
schemaData.setUpperCaseSubject(subject.toUpperCase());
schemaData.setVersion(version);

JsonNode subjectNode = rootNode.get("properties").get("subject").get("properties");
JsonNode subjectContentNode = subjectNode.get("content").get("properties");
updateSubjectContentProperties(schemaData, subjectContentNode);
} catch (IOException e) {
log.error("Exception occurred while building schema data from Json schema {}", e.getMessage());
throw new IllegalStateException("Exception occurred while building schema data from Json schema ", e);
}
return schemaData;
}

private static void updateSubjectContentProperties(SchemaData schemaData, JsonNode subjectContentNode) {
Iterator<Map.Entry<String, JsonNode>> contentProps = subjectContentNode.fields();
List<SchemaData.ContentField> contentFields = new ArrayList<>();
List<SchemaData.ContentObjectField> contentObjectFields = new ArrayList<>();
while (contentProps.hasNext()) {
Map.Entry<String, JsonNode> contentMap = contentProps.next();
String contentField = contentMap.getKey();
String capitalizedContentField = StringUtils.capitalize(contentField);
JsonNode contentNode = contentMap.getValue();
if (!contentNode.get("type").asText().equals("object")) {
contentFields.add(new SchemaData.ContentField(contentField, capitalizedContentField, "String"));
} else {
schemaData.setObjectName(contentField);
schemaData.setCapitalizedObjectName(capitalizedContentField);
JsonNode contentObjectNode = contentNode.get("properties");
Iterator<String> contentObjectProps = contentObjectNode.fieldNames();
while (contentObjectProps.hasNext()) {
String contentObjField = contentObjectProps.next();
String capitalizedContentObjField = StringUtils.capitalize(contentObjField);
contentObjectFields.add(new SchemaData.ContentObjectField(contentObjField,
capitalizedContentObjField, contentField, capitalizedContentField, "String"));
}
}
}
schemaData.setContentFields(contentFields);
schemaData.setContentObjectFields(contentObjectFields);
}

private static String getFieldsDataType(String fieldName) {
if (fieldName.equalsIgnoreCase("url")) {
return "URI";
} else {
return "String";
}
}
}
Loading

0 comments on commit 739fb09

Please sign in to comment.