blob: 810d5cf0283ec2146bd610798ca042696d41bff3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); 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 org.apache.camel.k.tooling.maven;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import org.apache.camel.catalog.DefaultCamelCatalog;
import org.apache.camel.catalog.quarkus.QuarkusRuntimeProvider;
import org.apache.camel.impl.engine.AbstractCamelContext;
import org.apache.camel.k.catalog.model.CamelArtifact;
import org.apache.camel.k.catalog.model.CamelCapability;
import org.apache.camel.k.catalog.model.CamelLoader;
import org.apache.camel.k.catalog.model.CamelScheme;
import org.apache.camel.k.catalog.model.CatalogComponentDefinition;
import org.apache.camel.k.catalog.model.CatalogDataFormatDefinition;
import org.apache.camel.k.catalog.model.CatalogDefinition;
import org.apache.camel.k.catalog.model.CatalogLanguageDefinition;
import org.apache.camel.k.catalog.model.CatalogOtherDefinition;
import org.apache.camel.k.catalog.model.CatalogSupport;
import org.apache.camel.k.catalog.model.k8s.ObjectMeta;
import org.apache.camel.k.catalog.model.k8s.crd.CamelCatalog;
import org.apache.camel.k.catalog.model.k8s.crd.CamelCatalogSpec;
import org.apache.camel.k.catalog.model.k8s.crd.RuntimeSpec;
import org.apache.camel.k.tooling.maven.support.MavenSupport;
import org.apache.camel.quarkus.core.FastCamelContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
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;
@Mojo(
name = "generate-catalog",
defaultPhase = LifecyclePhase.GENERATE_RESOURCES,
threadSafe = true,
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class GenerateCatalogMojo extends AbstractMojo {
private static final List<String> KNOWN_HTTP_URIS = Arrays.asList(
"ahc",
"ahc-ws",
"atmosphere-websocket",
"cxf",
"cxfrs",
"grpc",
"jetty",
"knative",
"netty-http",
"platform-http",
"rest",
"restlet",
"servlet",
"spark-rest",
"spring-ws",
"undertow",
"webhook",
"websocket"
);
private static final List<String> KNOWN_PASSIVE_URIS = Arrays.asList(
"bean",
"binding",
"browse",
"class",
"controlbus",
"dataformat",
"dataset",
"direct",
"direct-vm",
"language",
"log",
"mock",
"ref",
"seda",
"stub",
"test",
"validator",
"vm"
);
@Parameter(property = "catalog.path", defaultValue = "${project.build.directory}")
private String outputPath;
@Parameter(property = "catalog.file", defaultValue = "camel-catalog-${runtime.version}.yaml")
private String outputFile;
@Parameter(property = "components.exclusion.list")
private Set<String> componentsExclusionList;
@Parameter(property = "dataformats.exclusion.list")
private Set<String> dataformatsExclusionList;
@Parameter(property = "languages.exclusion.list")
private Set<String> languagesExclusionList;
@Parameter(property = "others.exclusion.list")
private Set<String> othersExclusionList;
@Parameter(property = "dsls.exclusion.list")
private Set<String> dslsExclusionList;
@Parameter(property = "capabilities.exclusion.list")
private Set<String> capabilitiesExclusionList;
// ********************
//
// ********************
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
final Path output = Paths.get(this.outputPath, this.outputFile);
try {
if (Files.notExists(output.getParent())) {
Files.createDirectories(output.getParent());
}
if (Files.exists(output)) {
Files.delete(output);
}
} catch (IOException e) {
throw new MojoExecutionException("Exception while generating camel catalog", e);
}
final org.apache.camel.catalog.CamelCatalog catalog = new DefaultCamelCatalog();
catalog.setRuntimeProvider(new QuarkusRuntimeProvider());
final String runtimeVersion = MavenSupport.getVersion(getClass(), "/META-INF/maven/org.apache.camel.k/camel-k-maven-plugin/pom.properties");
final String catalogName = String.format("camel-catalog-%s", runtimeVersion.toLowerCase(Locale.US));
try {
CamelCatalogSpec.Builder catalogSpec = new CamelCatalogSpec.Builder();
RuntimeSpec.Builder runtimeSpec = new RuntimeSpec.Builder()
.version(runtimeVersion)
.provider("quarkus");
MavenSupport.getVersion(
AbstractCamelContext.class,
"org.apache.camel", "camel-base",
version -> runtimeSpec.putMetadata("camel.version", version));
MavenSupport.getVersion(
FastCamelContext.class,
"io.quarkus", "quarkus-core",
version -> runtimeSpec.putMetadata("quarkus.version", version));
MavenSupport.getVersion(
QuarkusRuntimeProvider.class,
"org.apache.camel.quarkus", "camel-quarkus-catalog",
version -> runtimeSpec.putMetadata("camel-quarkus.version", version));
runtimeSpec.putMetadata("quarkus.native-builder-image", MavenSupport.getApplicationProperty(getClass(), "quarkus.native-builder-image"));
runtimeSpec.applicationClass("io.quarkus.bootstrap.runner.QuarkusEntryPoint");
runtimeSpec.addDependency("org.apache.camel.k", "camel-k-runtime");
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("cron")) {
runtimeSpec.putCapability(
"cron",
CamelCapability.forArtifact(
"org.apache.camel.k", "camel-k-cron"));
catalogSpec.putArtifact(
new CamelArtifact.Builder()
.groupId("org.apache.camel.k")
.artifactId("camel-k-cron")
.build()
);
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("health")) {
runtimeSpec.putCapability(
"health",
CamelCapability.forArtifact(
"org.apache.camel.quarkus", "camel-quarkus-microprofile-health"));
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("platform-http")) {
runtimeSpec.putCapability(
"platform-http",
CamelCapability.forArtifact(
"org.apache.camel.quarkus", "camel-quarkus-platform-http"));
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("rest")) {
runtimeSpec.putCapability(
"rest",
new CamelCapability.Builder()
.addDependency("org.apache.camel.quarkus", "camel-quarkus-rest")
.addDependency("org.apache.camel.quarkus", "camel-quarkus-platform-http")
.build());
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("circuit-breaker")) {
runtimeSpec.putCapability(
"circuit-breaker",
CamelCapability.forArtifact(
"org.apache.camel.quarkus", "camel-quarkus-microprofile-fault-tolerance"));
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("tracing")) {
runtimeSpec.putCapability(
"tracing",
CamelCapability.forArtifact(
"org.apache.camel.quarkus", "camel-quarkus-opentracing"));
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("telemetry")) {
runtimeSpec.putCapability(
"telemetry",
CamelCapability.forArtifact(
"org.apache.camel.quarkus", "camel-quarkus-opentelemetry"));
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("master")) {
runtimeSpec.putCapability(
"master",
CamelCapability.forArtifact(
"org.apache.camel.k", "camel-k-master"));
catalogSpec.putArtifact(
new CamelArtifact.Builder()
.groupId("org.apache.camel.k")
.artifactId("camel-k-master")
.build()
);
}
if (capabilitiesExclusionList != null && !capabilitiesExclusionList.contains("resume-kafka")) {
runtimeSpec.putCapability(
"resume-kafka",
CamelCapability.forArtifact(
"org.apache.camel.k", "camel-k-resume-kafka"));
catalogSpec.putArtifact(
new CamelArtifact.Builder()
.groupId("org.apache.camel.k")
.artifactId("camel-k-resume-kafka")
.build()
);
}
catalogSpec.runtime(runtimeSpec.build());
process(catalog, catalogSpec);
ObjectMeta.Builder metadata = new ObjectMeta.Builder()
.name(catalogName)
.putLabels("app", "camel-k")
.putLabels("camel.apache.org/catalog.version", catalog.getCatalogVersion())
.putLabels("camel.apache.org/catalog.loader.version", catalog.getLoadedVersion())
.putLabels("camel.apache.org/runtime.version", runtimeVersion);
CamelCatalog cr = new CamelCatalog.Builder()
.metadata(metadata.build())
.spec(catalogSpec.build())
.build();
//
// apiVersion: camel.apache.org/v1
// kind: CamelCatalog
// metadata:
// name: catalog-x.y.z-main
// labels:
// app: "camel-k"
// camel.apache.org/catalog.version: x.y.x
// camel.apache.org/catalog.loader.version: x.y.z
// camel.apache.org/runtime.version: x.y.x
// camel.apache.org/runtime.provider: main
// spec:
// version:
// runtimeVersion:
// status:
// artifacts:
//
try (Writer writer = Files.newBufferedWriter(output, StandardCharsets.UTF_8)) {
YAMLFactory factory = new YAMLFactory()
.configure(YAMLGenerator.Feature.MINIMIZE_QUOTES, true)
.configure(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS, true)
.configure(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID, false)
.configure(YAMLGenerator.Feature.WRITE_DOC_START_MARKER, false);
// write license header
writer.write(
GenerateSupport.getResourceAsString("/catalog-license.txt")
);
getLog().info("Writing catalog file to: " + output);
// write catalog data
ObjectMapper mapper = new ObjectMapper(factory);
mapper.registerModule(new Jdk8Module());
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
mapper.writeValue(writer, cr);
}
} catch (IOException e) {
throw new MojoExecutionException("Exception while generating catalog", e);
}
}
// ********************
//
// ********************
public void process(
org.apache.camel.catalog.CamelCatalog catalog,
CamelCatalogSpec.Builder specBuilder) {
Map<String, CamelArtifact> artifacts = new TreeMap<>();
processComponents(catalog, artifacts);
processLanguages(catalog, artifacts);
processDataFormats(catalog, artifacts);
processOthers(catalog, artifacts);
processLoaders(specBuilder);
specBuilder.putAllArtifacts(artifacts);
}
private void processLoaders(CamelCatalogSpec.Builder specBuilder) {
if (dslsExclusionList != null) {
getLog().info("dsls.exclusion.list: " + dslsExclusionList);
}
if (dslsExclusionList != null && !dslsExclusionList.contains("yaml")) {
specBuilder.putLoader(
"yaml",
CamelLoader.fromArtifact("org.apache.camel.quarkus", "camel-quarkus-yaml-dsl")
.addLanguage("yaml")
.putMetadata("native", "true")
.build()
);
}
if (dslsExclusionList != null && !dslsExclusionList.contains("groovy")) {
specBuilder.putLoader(
"groovy",
CamelLoader.fromArtifact("org.apache.camel.quarkus", "camel-quarkus-groovy-dsl")
.addLanguage("groovy")
.putMetadata("native", "true")
.putMetadata("sources-required-at-build-time", "true")
.build()
);
}
if (dslsExclusionList != null && !dslsExclusionList.contains("kts")) {
specBuilder.putLoader(
"kts",
CamelLoader.fromArtifact("org.apache.camel.quarkus", "camel-quarkus-kotlin-dsl")
.addLanguage("kts")
.putMetadata("native", "true")
.putMetadata("sources-required-at-build-time", "true")
.build()
);
}
if (dslsExclusionList != null && !dslsExclusionList.contains("js")) {
specBuilder.putLoader(
"js",
CamelLoader.fromArtifact("org.apache.camel.quarkus", "camel-quarkus-js-dsl")
.addLanguage("js")
// Guest languages are not yet supported on Mandrel in native mode.
.putMetadata("native", "false")
.build()
);
}
if (dslsExclusionList != null && !dslsExclusionList.contains("xml")) {
specBuilder.putLoader(
"xml",
CamelLoader.fromArtifact("org.apache.camel.quarkus", "camel-quarkus-xml-io-dsl")
.addLanguage("xml")
.putMetadata("native", "true")
.build()
);
}
if (dslsExclusionList != null && !dslsExclusionList.contains("java")) {
specBuilder.putLoader(
"java",
CamelLoader.fromArtifact("org.apache.camel.quarkus", "camel-quarkus-java-joor-dsl")
.addLanguages("java")
.putMetadata("native", "true")
.putMetadata("sources-required-at-build-time", "true")
.build()
);
}
if (dslsExclusionList != null && !dslsExclusionList.contains("jsh")) {
specBuilder.putLoader(
"jsh",
CamelLoader.fromArtifact("org.apache.camel.quarkus", "camel-quarkus-jsh-dsl")
.addLanguages("jsh")
// Native mode is not yet supported due to https://github.com/apache/camel-quarkus/issues/4458.
.putMetadata("native", "false")
.putMetadata("sources-required-at-build-time", "true")
.build()
);
}
}
private void processComponents(org.apache.camel.catalog.CamelCatalog catalog, Map<String, CamelArtifact> artifacts) {
final Set<String> elements = new TreeSet<>(catalog.findComponentNames());
if (componentsExclusionList != null) {
getLog().info("components.exclusion.list: " + componentsExclusionList);
elements.removeAll(componentsExclusionList);
}
for (String name : elements) {
String json = catalog.componentJSonSchema(name);
CatalogComponentDefinition definition = CatalogSupport.unmarshallComponent(json);
artifacts.compute(definition.getArtifactId(), (key, artifact) -> {
CamelArtifact.Builder builder = artifactBuilder(artifact, definition);
builder.addJavaType(definition.getJavaType());
definition.getSchemes().map(StringUtils::trimToNull).filter(Objects::nonNull).forEach(scheme -> {
builder.addScheme(
new CamelScheme.Builder()
.id(scheme)
.http(KNOWN_HTTP_URIS.contains(scheme))
.passive(KNOWN_PASSIVE_URIS.contains(scheme))
.build());
});
return builder.build();
});
}
}
private void processLanguages(org.apache.camel.catalog.CamelCatalog catalog, Map<String, CamelArtifact> artifacts) {
final Set<String> elements = new TreeSet<>(catalog.findLanguageNames());
if (languagesExclusionList != null) {
getLog().info("languages.exclusion.list: " + languagesExclusionList);
elements.removeAll(languagesExclusionList);
}
for (String name : elements) {
String json = catalog.languageJSonSchema(name);
CatalogLanguageDefinition definition = CatalogSupport.unmarshallLanguage(json);
artifacts.compute(definition.getArtifactId(), (key, artifact) -> {
CamelArtifact.Builder builder = artifactBuilder(artifact, definition);
builder.addLanguage(definition.getName());
builder.addJavaType(definition.getJavaType());
return builder.build();
});
}
}
private void processDataFormats(org.apache.camel.catalog.CamelCatalog catalog, Map<String, CamelArtifact> artifacts) {
final Set<String> elements = new TreeSet<>(catalog.findDataFormatNames());
if (dataformatsExclusionList != null) {
getLog().info("dataformats.exclusion.list: " + dataformatsExclusionList);
elements.removeAll(dataformatsExclusionList);
}
for (String name : elements) {
String json = catalog.dataFormatJSonSchema(name);
CatalogDataFormatDefinition definition = CatalogSupport.unmarshallDataFormat(json);
artifacts.compute(definition.getArtifactId(), (key, artifact) -> {
CamelArtifact.Builder builder = artifactBuilder(artifact, definition);
builder.addDataformat(definition.getName());
builder.addJavaType(definition.getJavaType());
return builder.build();
});
}
}
private void processOthers(org.apache.camel.catalog.CamelCatalog catalog, Map<String, CamelArtifact> artifacts) {
final Set<String> elements = new TreeSet<>(catalog.findOtherNames());
if (othersExclusionList != null) {
getLog().info("others.exclusion.list: " + othersExclusionList);
elements.removeAll(othersExclusionList);
}
for (String name : elements) {
String json = catalog.otherJSonSchema(name);
CatalogOtherDefinition definition = CatalogSupport.unmarshallOther(json);
artifacts.compute(definition.getArtifactId(), (key, artifact) -> artifactBuilder(artifact, definition).build());
}
}
private CamelArtifact.Builder artifactBuilder(CamelArtifact artifact, CatalogDefinition definition) {
CamelArtifact.Builder builder = new CamelArtifact.Builder();
if (artifact != null) {
builder.from(artifact);
} else {
Objects.requireNonNull(definition.getGroupId());
Objects.requireNonNull(definition.getArtifactId());
builder.groupId(definition.getGroupId());
builder.artifactId(definition.getArtifactId());
}
return builder;
}
}