diff --git a/connector-sdk/element-template-generator-maven-plugin/README.md b/connector-sdk/element-template-generator-maven-plugin/README.md new file mode 100644 index 0000000000..d0e33b86b7 --- /dev/null +++ b/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 + + io.camunda.connector + element-template-generator-maven-plugin + ${version} + + + + generate-templates + + + + + + io.camunda.connector.MyConnector + + + +``` + +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 + + + io.camunda.connector.MyConnector + + + io.camunda.connector:my-connector-library + + +``` + +Note that the plugin will not resolve transitive dependencies of the specified dependencies. diff --git a/connector-sdk/element-template-generator-maven-plugin/pom.xml b/connector-sdk/element-template-generator-maven-plugin/pom.xml new file mode 100644 index 0000000000..ee29c31947 --- /dev/null +++ b/connector-sdk/element-template-generator-maven-plugin/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + + + io.camunda.connector + connector-parent + ../../parent/pom.xml + 0.23.0-SNAPSHOT + + + element-template-generator-maven-plugin + Maven plugin for generating connector templates + element-template-generator-maven-plugin + maven-plugin + + + 3.9.4 + 3.9.0 + 3.9.0 + 2.2.1 + + + + + io.camunda.connector + element-template-generator + + + + org.apache.maven + maven-plugin-api + ${version.maven-plugin-api} + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${version.maven-plugin-annotations} + provided + + + org.apache.maven + maven-project + ${version.maven-project} + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + ${version.maven-plugin-plugin} + + + default-descriptor + process-classes + + + + + + \ No newline at end of file diff --git a/connector-sdk/element-template-generator-maven-plugin/src/main/java/io/camunda/connector/generator/ElementTemplateGeneratorMojo.java b/connector-sdk/element-template-generator-maven-plugin/src/main/java/io/camunda/connector/generator/ElementTemplateGeneratorMojo.java new file mode 100644 index 0000000000..ec920fb301 --- /dev/null +++ b/connector-sdk/element-template-generator-maven-plugin/src/main/java/io/camunda/connector/generator/ElementTemplateGeneratorMojo.java @@ -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 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"; + } +} diff --git a/connectors/pom.xml b/connectors/pom.xml index 6d83b35db6..eaf3fce052 100644 --- a/connectors/pom.xml +++ b/connectors/pom.xml @@ -112,6 +112,19 @@ except in compliance with the proprietary license. + + io.camunda.connector + element-template-generator-maven-plugin + ${project.version} + + + + generate-templates + + + + + org.apache.maven.plugins maven-shade-plugin diff --git a/pom.xml b/pom.xml index e2b84008a9..ba9537d108 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ connector-sdk/test connector-sdk/jackson-datatype-feel connector-sdk/element-template-generator + connector-sdk/element-template-generator-maven-plugin secret-providers/gcp-secret-provider connector-runtime/connector-runtime-core connector-runtime/connector-runtime-spring