Skip to content

Commit

Permalink
feat(generator): template generator Maven plugin (#1106)
Browse files Browse the repository at this point in the history
* feat(generator): add Maven plugin to generate templates

* set maven plugin plugin version

* Make output directory configurable
  • Loading branch information
chillleader committed Sep 5, 2023
1 parent 3931837 commit f133557
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 0 deletions.
57 changes: 57 additions & 0 deletions connector-sdk/element-template-generator-maven-plugin/README.md
@@ -0,0 +1,57 @@
# Element Template Generator Maven Plugin

This plugin generates [Connector Templates](https://docs.camunda.io/docs/components/connectors/custom-built-connectors/connector-templates/)
based on Connector code.

To use the plugin, your Connector must be annotated with `@ElementTemplate` annotation.
See the [Element Template Generator](../element-template-generator) module for more information.

## Usage

Add the following plugin to your `pom.xml`:

```xml
<plugin>
<groupId>io.camunda.connector</groupId>
<artifactId>element-template-generator-maven-plugin</artifactId>
<version>${version}</version>
<executions>
<execution>
<goals>
<goal>generate-templates</goal>
</goals>
</execution>
</executions>
<configuration>
<connectorClasses>
<connectorClass>io.camunda.connector.MyConnector</connectorClass>
</connectorClasses>
</configuration>
</plugin>
```

Edit the `connectorClass` element to point to your Connector class. You can specify multiple
classes if you have more than one Connector in one project.

By default, the generated element template will be placed in `element-templates` directory inside
your project's base directory. You can change the output directory by setting the `outputDirectory`
configuration parameter.

## Accessing classes from other modules

If your Connector definition references classes from other modules, the plugin will not be able
to find them automatically. You can add direct dependencies of your project to the plugin classpath
by adding the following configuration to the plugin:

```xml
<configuration>
<connectorClasses>
<connectorClass>io.camunda.connector.MyConnector</connectorClass>
</connectorClasses>
<includeDependencies>
<includeDependency>io.camunda.connector:my-connector-library</includeDependency>
</includeDependencies>
</configuration>
```

Note that the plugin will not resolve transitive dependencies of the specified dependencies.
63 changes: 63 additions & 0 deletions connector-sdk/element-template-generator-maven-plugin/pom.xml
@@ -0,0 +1,63 @@
<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>io.camunda.connector</groupId>
<artifactId>connector-parent</artifactId>
<relativePath>../../parent/pom.xml</relativePath>
<version>0.23.0-SNAPSHOT</version>
</parent>

<name>element-template-generator-maven-plugin</name>
<description>Maven plugin for generating connector templates</description>
<artifactId>element-template-generator-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>

<properties>
<version.maven-plugin-api>3.9.4</version.maven-plugin-api>
<version.maven-plugin-annotations>3.9.0</version.maven-plugin-annotations>
<version.maven-plugin-plugin>3.9.0</version.maven-plugin-plugin>
<version.maven-project>2.2.1</version.maven-project>
</properties>

<dependencies>
<dependency>
<groupId>io.camunda.connector</groupId>
<artifactId>element-template-generator</artifactId>
</dependency>

<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>${version.maven-plugin-api}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>${version.maven-plugin-annotations}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>${version.maven-project}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>${version.maven-plugin-plugin}</version>
<executions>
<execution>
<id>default-descriptor</id>
<phase>process-classes</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,130 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.camunda.connector.generator;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.camunda.connector.generator.core.OutboundElementTemplateGenerator;
import io.camunda.connector.generator.dsl.OutboundElementTemplate;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;

@Mojo(
name = "generate-templates",
defaultPhase = LifecyclePhase.PROCESS_CLASSES,
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class ElementTemplateGeneratorMojo extends AbstractMojo {

@Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;

@Parameter(property = "connectorClasses", required = true)
private String[] connectorClasses;

@Parameter(property = "includeDependencies")
private String[] includeDependencies;

@Parameter(property = "outputDirectory", defaultValue = "${project.basedir}/element-templates")
private String outputDirectory;

private static final ObjectMapper mapper = new ObjectMapper();
private final OutboundElementTemplateGenerator generator = new OutboundElementTemplateGenerator();

private static final String COMPILED_CLASSES_DIR = "target" + File.separator + "classes";

@Override
public void execute() throws MojoFailureException {
if (connectorClasses.length == 0) {
getLog().warn("No connector classes specified. Skipping generation of element templates.");
return;
}

List<URL> classpathUrls = new ArrayList<>();

try {
String compiledClassesPath =
project.getFile().getParent() + File.separator + COMPILED_CLASSES_DIR;
classpathUrls.add(new File(compiledClassesPath).toURI().toURL());

for (String dependency : includeDependencies) {
Artifact dependencyArtifact = (Artifact) project.getArtifactMap().get(dependency);
if (dependencyArtifact == null) {
throw new IllegalArgumentException(
"Failed to find dependency " + dependency + " in project " + project.getName());
}
classpathUrls.add(dependencyArtifact.getFile().toURI().toURL());
}
} catch (Exception e) {
throw new MojoFailureException("Failed to load classpath: " + e.getMessage(), e);
}

try (URLClassLoader classLoader =
new URLClassLoader(
classpathUrls.toArray(new URL[0]), Thread.currentThread().getContextClassLoader())) {

for (String className : connectorClasses) {
getLog().info("Generating element template for " + className);
Class<?> clazz = classLoader.loadClass(className);
OutboundElementTemplate template = generateElementTemplate(clazz);
writeElementTemplate(template);
}

} catch (ClassNotFoundException e) {
throw new MojoFailureException("Failed to find connector class: " + e.getMessage(), e);
} catch (TypeNotPresentException e) {
throw new MojoFailureException(
e.getMessage()
+ "\nIf your connector references other packages, include them using the 'includeDependencies' parameter",
e);
} catch (Exception e) {
throw new MojoFailureException("Failed to generate element templates: " + e.getMessage(), e);
}
}

private OutboundElementTemplate generateElementTemplate(Class<?> clazz) {
return generator.generate(clazz);
}

private void writeElementTemplate(OutboundElementTemplate template) {
try {
String fileName = transformConnectorNameToTemplateFileName(template.name());
File file = new File(outputDirectory, fileName);
file.getParentFile().mkdirs();
mapper.writerWithDefaultPrettyPrinter().writeValue(file, template);
} catch (Exception e) {
throw new RuntimeException("Failed to write element template", e);
}
}

private String transformConnectorNameToTemplateFileName(String connectorName) {
// convert human-oriented name to kebab-case
connectorName = connectorName.replaceAll(" ", "-");
connectorName = connectorName.replaceAll("([a-z])([A-Z]+)", "$1-$2");
connectorName = connectorName.toLowerCase();
return connectorName + ".json";
}
}
13 changes: 13 additions & 0 deletions connectors/pom.xml
Expand Up @@ -112,6 +112,19 @@ except in compliance with the proprietary license.</license.inlineheader>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>io.camunda.connector</groupId>
<artifactId>element-template-generator-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>generate-templates</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Expand Up @@ -24,6 +24,7 @@
<module>connector-sdk/test</module>
<module>connector-sdk/jackson-datatype-feel</module>
<module>connector-sdk/element-template-generator</module>
<module>connector-sdk/element-template-generator-maven-plugin</module>
<module>secret-providers/gcp-secret-provider</module>
<module>connector-runtime/connector-runtime-core</module>
<module>connector-runtime/connector-runtime-spring</module>
Expand Down

0 comments on commit f133557

Please sign in to comment.