You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/03/14 18:49:01 UTC
(camel) 01/10: CAMEL-17641: Generate json metadata for pojo beans in camel-core that end users can use such as AggregationStrategy implementations. And have that information in camel-catalog for tooling assistance.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch pojo-beans
in repository https://gitbox.apache.org/repos/asf/camel.git
commit a0d5fa9fbd1355aa0e95ff144d536f29b91d3b4d
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Mar 14 15:23:17 2024 +0100
CAMEL-17641: Generate json metadata for pojo beans in camel-core that end users can use such as AggregationStrategy implementations. And have that information in camel-catalog for tooling assistance.
---
.../aggregate/UseLatestAggregationStrategy.java | 9 +-
.../maven/packaging/GenerateComponentMojo.java | 2 +
.../apache/camel/maven/packaging/GenerateMojo.java | 2 +
.../maven/packaging/GeneratePojoBeanMojo.java | 221 +++++++++++++++++++++
4 files changed, 232 insertions(+), 2 deletions(-)
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/UseLatestAggregationStrategy.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/UseLatestAggregationStrategy.java
index d43a6a7fa76..eb48f844d81 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/UseLatestAggregationStrategy.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/UseLatestAggregationStrategy.java
@@ -19,12 +19,17 @@ package org.apache.camel.processor.aggregate;
import org.apache.camel.AggregationStrategy;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePropertyKey;
+import org.apache.camel.spi.Metadata;
/**
* An {@link AggregationStrategy} which just uses the latest exchange which is useful for status messages where old
* status messages have no real value. Another example is things like market data prices, where old stock prices are not
* that relevant, only the current price is.
*/
+@Metadata(label = "bean",
+ description = "An AggregationStrategy which just uses the latest exchange which is useful for status messages where old"
+ + " status messages have no real value. Another example is things like market data prices, where old stock prices are not"
+ + " that relevant, only the current price is.")
public class UseLatestAggregationStrategy implements AggregationStrategy {
@Override
@@ -72,8 +77,8 @@ public class UseLatestAggregationStrategy implements AggregationStrategy {
// propagate exception from old exchange if there isn't already an exception
if (oldExchange.isFailed() || oldExchange.isRollbackOnly() || oldExchange.isRollbackOnlyLast()
- || oldExchange.getExchangeExtension().isErrorHandlerHandledSet()
- && oldExchange.getExchangeExtension().isErrorHandlerHandled()) {
+ || oldExchange.getExchangeExtension().isErrorHandlerHandledSet()
+ && oldExchange.getExchangeExtension().isErrorHandlerHandled()) {
// propagate failure by using old exchange as the answer
return oldExchange;
}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateComponentMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateComponentMojo.java
index 54e8563c891..d20cd9aaa7c 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateComponentMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateComponentMojo.java
@@ -50,6 +50,8 @@ public class GenerateComponentMojo extends AbstractGenerateMojo {
invoke(GenerateInvokeOnHeaderMojo.class);
// generate data-type-transformer
invoke(GenerateDataTypeTransformerMojo.class);
+ // generate pojo-beans
+ invoke(GeneratePojoBeanMojo.class);
// generate dev-console
invoke(GenerateDevConsoleMojo.class);
// prepare-components
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateMojo.java
index 982f872be20..84b7d2752d2 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateMojo.java
@@ -52,6 +52,8 @@ public class GenerateMojo extends AbstractGenerateMojo {
invoke(GenerateInvokeOnHeaderMojo.class);
// generate data-type-transformer
invoke(GenerateDataTypeTransformerMojo.class);
+ // generate pojo-beans
+ invoke(GeneratePojoBeanMojo.class);
// generate dev-console
invoke(GenerateDevConsoleMojo.class);
// prepare-components
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GeneratePojoBeanMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GeneratePojoBeanMojo.java
new file mode 100644
index 00000000000..31fc4fc4ca3
--- /dev/null
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GeneratePojoBeanMojo.java
@@ -0,0 +1,221 @@
+/*
+ * 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.maven.packaging;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.StringJoiner;
+
+import org.apache.camel.maven.packaging.generics.PackagePluginUtils;
+import org.apache.camel.tooling.util.PackageHelper;
+import org.apache.camel.tooling.util.Strings;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+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;
+import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.Index;
+
+import static org.apache.camel.maven.packaging.MojoHelper.annotationValue;
+
+/**
+ * Factory for generating code for Camel pojo beans that are intended for end user to use with Camel EIPs and
+ * components.
+ */
+@Mojo(name = "generate-pojo-bean", threadSafe = true, defaultPhase = LifecyclePhase.PROCESS_CLASSES,
+ requiresDependencyCollection = ResolutionScope.COMPILE,
+ requiresDependencyResolution = ResolutionScope.COMPILE)
+public class GeneratePojoBeanMojo extends AbstractGeneratorMojo {
+
+ public static final DotName METADATA = DotName.createSimple("org.apache.camel.spi.Metadata");
+
+ /**
+ * The project build directory
+ */
+ @Parameter(defaultValue = "${project.build.directory}")
+ protected File buildDir;
+
+ @Parameter(defaultValue = "${project.basedir}/src/generated/resources")
+ protected File resourcesOutputDir;
+
+ private static class BeanPojoModel {
+ private String name;
+ private String className;
+ private String interfaceName;
+ private String description;
+ private boolean deprecated;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public String getInterfaceName() {
+ return interfaceName;
+ }
+
+ public void setInterfaceName(String interfaceName) {
+ this.interfaceName = interfaceName;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public boolean isDeprecated() {
+ return deprecated;
+ }
+
+ public void setDeprecated(boolean deprecated) {
+ this.deprecated = deprecated;
+ }
+ }
+
+ public GeneratePojoBeanMojo() {
+ }
+
+ @Override
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ if ("pom".equals(project.getPackaging())) {
+ return;
+ }
+
+ buildDir = new File(project.getBuild().getDirectory());
+
+ if (resourcesOutputDir == null) {
+ resourcesOutputDir = new File(project.getBasedir(), "src/generated/resources");
+ }
+
+ Index index = PackagePluginUtils.readJandexIndexIgnoreMissing(project, getLog());
+ if (index == null) {
+ return;
+ }
+
+ List<BeanPojoModel> models = new ArrayList<>();
+ List<AnnotationInstance> annotations = index.getAnnotations(METADATA);
+ annotations.forEach(a -> {
+ // only @Metadata(label="bean") is selected
+ String label = annotationValue(a, "label");
+ if ("bean".equals(label)) {
+ BeanPojoModel model = new BeanPojoModel();
+ String currentClass = a.target().asClass().name().toString();
+ boolean deprecated = a.target().asClass().hasAnnotation(Deprecated.class);
+ model.setName(a.target().asClass().simpleName());
+ model.setClassName(currentClass);
+ model.setDeprecated(deprecated);
+ model.setDescription(annotationValue(a, "description"));
+ for (DotName dn : a.target().asClass().interfaceNames()) {
+ if (dn.packagePrefix().startsWith("org.apache.camel")) {
+ model.setInterfaceName(dn.toString());
+ break;
+ }
+ }
+ // TODO: getter/setter for options ala EIP/components
+ models.add(model);
+ }
+ });
+ models.sort(Comparator.comparing(BeanPojoModel::getClassName));
+
+ if (!models.isEmpty()) {
+ try {
+ StringJoiner names = new StringJoiner(" ");
+ for (var model : models) {
+ names.add(model.getClassName());
+ JsonObject jo = asJsonObject(model);
+ String json = jo.toJson();
+ json = Jsoner.prettyPrint(json, 2);
+ String fn = sanitizeFileName(model.getName()) + PackageHelper.JSON_SUFIX;
+ boolean updated = updateResource(resourcesOutputDir.toPath(),
+ "META-INF/services/org/apache/camel/bean/" + fn,
+ json + NL);
+ if (updated) {
+ getLog().info("Updated bean json: " + model.getName());
+ }
+ }
+
+ // generate marker file
+ File camelMetaDir = new File(resourcesOutputDir, "META-INF/services/org/apache/camel/");
+ int count = models.size();
+ String properties = createProperties(project, "beans", names.toString());
+ updateResource(camelMetaDir.toPath(), "beans.properties", properties);
+ getLog().info("Generated beans.properties containing " + count + " Camel "
+ + (count > 1 ? "beans: " : "bean: ") + names);
+ } catch (Exception e) {
+ throw new MojoExecutionException(e);
+ }
+ }
+ }
+
+ private JsonObject asJsonObject(BeanPojoModel model) {
+ JsonObject jo = new JsonObject();
+ // we need to know the maven GAV also
+ jo.put("kind", "bean");
+ jo.put("name", model.getName());
+ jo.put("javaType", model.getClassName());
+ if (model.getInterfaceName() != null) {
+ jo.put("interfaceType", model.getInterfaceName());
+ }
+ jo.put("title", asTitle(model.getClassName()));
+ if (model.getDescription() != null) {
+ jo.put("description", model.getDescription());
+ }
+ jo.put("deprecated", model.isDeprecated());
+ jo.put("groupId", project.getGroupId());
+ jo.put("artifactId", project.getArtifactId());
+ jo.put("version", project.getVersion());
+ JsonObject root = new JsonObject();
+ root.put("bean", jo);
+ return root;
+ }
+
+ private String sanitizeFileName(String fileName) {
+ return fileName.replaceAll("[^A-Za-z0-9+-/]", "-");
+ }
+
+ private String asTitle(String name) {
+ name = Strings.camelDashToTitle(name);
+ String part = Strings.after(name, ":");
+ if (part != null) {
+ part = Strings.capitalize(part);
+ name = Strings.before(name, ":") + " (" + part + ")";
+ }
+ return name;
+ }
+
+}