Document health, metrics & OpenTracing extensions
diff --git a/docs/modules/ROOT/pages/extensions/microprofile-health.adoc b/docs/modules/ROOT/pages/extensions/microprofile-health.adoc
new file mode 100644
index 0000000..111486b
--- /dev/null
+++ b/docs/modules/ROOT/pages/extensions/microprofile-health.adoc
@@ -0,0 +1,57 @@
+[[microprofile-health]]
+= MicroProfile Health Extension
+
+*Available as of Camel Quarkus version 0.21*
+
+The MicroProfile Health extension bridges the Camel health check API with MicroProfile Metrics & SmallRye Health.
+
+Maven users will need to add the following dependency to their `pom.xml` for this extension.
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel.quarkus</groupId>
+    <artifactId>camel-quarkus-microprofile-health</artifactId>
+</dependency>
+------------------------------------------------------------
+
+== Usage
+
+You can register health checks for your applications with the https://camel.apache.org/manual/latest/health-check.html[Camel health check API].
+
+By default, classes extending `AbstractHealthCheck` are registered as both liveness and readiness checks. For finer control over whether
+a check is registered as a liveness or readiness check, you can extend either `AbstractCamelMicroProfileLivenessCheck` or `AbstractCamelMicroProfileReadinessCheck`.
+
+Any checks provided by your application are automatically discovered and bound to the Camel registry. They will be available via
+the Quarkus health endpoints `/health/live` and `/health/ready`.
+
+You can also provide custom `HealthCheckRepository` implementations and these are also automatically discovered and bound to the Camel registry for you.
+
+Refer to the https://quarkus.io/guides/health-guide[Quarkus health guide] for further information.
+
+=== Provided health checks
+
+Some checks are automatically registered for your application.
+
+==== Camel Context Health
+
+Inspects the Camel Context status and causes the health check status to be `DOWN` if the status is anything other than 'Started'.
+
+==== Camel Route Health
+
+Inspects the status of each route and causes the health check status to be `DOWN` if any route status is not 'Started'.
+
+=== Configuration
+
+The Camel MicroProfile Health extension exposes the following configuration properties.
+
+[cols="80,.^10,.^10"]
+|===
+|Configuration property |Type |Default
+
+|`quarkus.camel.health.enabled`
+
+ Set whether to enable Camel health checks
+|boolean
+|`true`
+|===
diff --git a/docs/modules/ROOT/pages/extensions/microprofile-metrics.adoc b/docs/modules/ROOT/pages/extensions/microprofile-metrics.adoc
new file mode 100644
index 0000000..4969915
--- /dev/null
+++ b/docs/modules/ROOT/pages/extensions/microprofile-metrics.adoc
@@ -0,0 +1,184 @@
+[[microprofile-metrics]]
+= MicroProfile Metrics Extension
+
+*Available as of Camel Quarkus version 0.21*
+
+The MicroProfile Metrics extension produces metrics and statistics related to the Camel Context, routes and message exchanges.
+
+Maven users will need to add the following dependency to their `pom.xml` for this extension.
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel.quarkus</groupId>
+    <artifactId>camel-quarkus-microprofile-metrics</artifactId>
+</dependency>
+------------------------------------------------------------
+
+== Usage
+
+The https://camel.apache.org/components/latest/microprofile-metrics-component.html[microprofile-metrics] component automatically exposes a set of Camel application metrics. Some of these include:
+
+=== Camel Context metrics
+
+[cols="80,.^20]
+|===
+|Metric Name | Type
+
+|`camel.context.status`
+
+The status of the Camel Context represented by the `ServiceStatus` enum ordinal
+
+| Gauge
+
+|`camel.context.uptime`
+
+The Camel Context uptime in milliseconds
+
+| Gauge
+
+|`camel.context.exchanges.completed.total`
+
+The total number of completed exchanges
+
+| Counter
+
+|`camel.context.exchanges.failed.total`
+
+The total number of failed exchanges
+
+| Counter
+
+|`camel.context.exchanges.inflight.total`
+
+The total number of inflight exchanges
+
+| Gauge
+
+|`camel.context.exchanges.total`
+
+The total number of all exchanges
+
+| Counter
+
+|`camel.context.externalRedeliveries.total`
+
+The total number of all external redeliveries
+
+| Counter
+
+|`camel.context.failuresHandled.total`
+
+The total number of all failures handled
+
+| Counter
+
+|===
+
+=== Camel Route metrics
+
+[cols="80,.^20]
+|===
+|Metric Name | Type
+
+|`camel.route.count`
+
+The number of routes
+
+| Gauge
+
+|`camel.route.running.count`
+
+The number of running routes
+
+| Gauge
+
+|`camel.route.exchanges.completed.total`
+
+The total number of completed exchanges for the route
+
+| Counter
+
+|`camel.route.exchanges.failed.total`
+
+The total number of failed exchanges for the route
+
+| Counter
+
+|`camel.route.exchanges.inflight.total`
+
+The total number of inflight exchanges for the route
+
+| Gauge
+
+|`camel.route.exchanges.total`
+
+The total number of all exchanges for the route
+
+| Counter
+
+|`camel.route.externalRedeliveries.total`
+
+The total number of all external redeliveries for the route
+
+| Counter
+
+|`camel.route.failuresHandled.total`
+
+The total number of all failures handled for the route
+
+| Counter
+|===
+
+All metrics are tagged with the name of the Camel Context and the id of the route where applicable.
+
+You can also produce your own customized metrics in your Camel routes. For more information, refer to the https://camel.apache.org/components/latest/microprofile-metrics-component.html[microprofile-metrics] component documentation.
+
+Metrics are exposed to Quarkus as application metrics and they can be browsed at http://localhost:8080/metrics/application.
+
+
+=== Configuration
+
+The Camel MicroProfile Metrics extension exposes the following configuration properties.
+
+[cols="80,.^10,.^10"]
+|===
+|Configuration property |Type |Default
+
+|`quarkus.camel.metrics.enable-route-policy`
+
+Set whether to enable the `MicroProfileMetricsRoutePolicyFactory` for capturing metrics on route processing times
+|boolean
+|`true`
+
+
+|`quarkus.camel.metrics.enable-message-history`
+
+Set whether to enable the `MicroProfileMetricsMessageHistoryFactory` for capturing metrics on individual route node processing times.
+
+Depending on the number of configured route nodes, there is the potential to create a large volume of metrics. Therefore, this option is disabled by default.
+
+|boolean
+|`false`
+
+|`quarkus.camel.metrics.enable-exchange-event-notifier`
+
+Set whether to enable the `MicroProfileMetricsExchangeEventNotifier` for capturing metrics on exchange processing times.
+
+|boolean
+|`true`
+
+|`quarkus.camel.metrics.enable-route-event-notifier`
+
+Set whether to enable the `MicroProfileMetricsRouteEventNotifier` for capturing metrics on the total number of routes and total number of routes running.
+
+|boolean
+|`true`
+
+|`quarkus.camel.metrics.enable-camel-context-event-notifier`
+
+Set whether to enable the `MicroProfileMetricsCamelContextEventNotifier` for capturing metrics about the CamelContext, such as status and uptime.
+
+|boolean
+|`true`
+|===
diff --git a/docs/modules/ROOT/pages/extensions/opentracing.adoc b/docs/modules/ROOT/pages/extensions/opentracing.adoc
new file mode 100644
index 0000000..c925e17
--- /dev/null
+++ b/docs/modules/ROOT/pages/extensions/opentracing.adoc
@@ -0,0 +1,59 @@
+[[opentracing]]
+= OpenTracing Extension
+
+*Available as of Camel Quarkus version 0.21*
+
+The OpenTracing extension is used for tracing and timing incoming and outgoing Camel messages.
+
+Maven users will need to add the following dependency to their `pom.xml` for this extension.
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel.quarkus</groupId>
+    <artifactId>camel-quarkus-opentracing</artifactId>
+</dependency>
+------------------------------------------------------------
+
+== Usage
+
+The extension automatically creates a Camel `OpenTracingTracer` and binds it to the Camel registry.
+
+In order to send the captured traces to a tracing system, you need to configure some properties within `application.properties` like those below.
+
+....
+quarkus.jaeger.service-name=my-service
+quarkus.jaeger.sampler-type=const
+quarkus.jaeger.sampler-param=1
+quarkus.jaeger.endpoint=http://localhost:14268/api/traces
+....
+
+Refer to the https://quarkus.io/guides/opentracing-guide#configuration-reference[Quarkus OpenTracing guide] for a full list of configuration options.
+
+Route endpoints can be excluded from tracing by configuring a property named `quarkus.camel.opentracing.exclude-patterns` in `application.properties`. For example:
+
+....
+# Exclude all direct & netty-http endpoints from tracing
+quarkus.camel.opentracing.exclude-patterns=direct:*,netty-http:*
+....
+
+=== Configuration
+
+The Camel OpenTracing extension exposes the following configuration properties.
+
+[cols="80,.^10,.^10"]
+|===
+|Configuration property |Type |Default
+
+|`quarkus.camel.opentracing.encoding`
+
+ Sets whether header keys need to be encoded
+|boolean
+|`false`
+
+|`quarkus.camel.opentracing.exclude-patterns`
+
+ Sets whether to disable tracing for endpoint URIs that match the given patterns
+|List<String>
+|
+|===
diff --git a/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc b/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc
index 09fa64b..a72534c 100644
--- a/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc
+++ b/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc
@@ -45,7 +45,7 @@
 | link:https://camel.apache.org/components/latest/mail-component.html[Mail] (camel-quarkus-mail) +
 `imap:host:port` | 0.2 | To send or receive emails using imap/pop3 or smtp protocols.
 
-| link:https://camel.apache.org/components/latest/microprofile-metrics-component.html[MicroProfile Metrics] (camel-quarkus-microprofile-metrics) +
+| xref:extensions/microprofile-metrics.adoc[MicroProfile Metrics] (camel-quarkus-microprofile-metrics) +
 `microprofile-metrics:metricType:metricName` | 0.2 | Camel metrics exposed with Eclipse MicroProfile Metrics
 
 | link:https://camel.apache.org/components/latest/netty-http-component.html[Netty HTTP] (camel-quarkus-netty-http) +
@@ -142,8 +142,8 @@
 
 | (camel-quarkus-reactive-executor) | 0.2.1 | To use Quarkus reactive executor with Camel
 
-| (camel-quarkus-microprofile-health) | 0.2.1 | Integration with the Quarkus MicroProfile Health extension
+| xref:extensions/microprofile-health.adoc[camel-quarkus-microprofile-health]  | 0.2.1 | Integration with the Quarkus MicroProfile Health extension
 
-| (camel-quarkus-opentracing) | 0.2.1 | Distributed tracing using OpenTracing
+| xref:extensions/opentracing.adoc[camel-quarkus-opentracing]  | 0.2.1 | Distributed tracing using OpenTracing
 |===
 // others: END
diff --git a/extensions/readme.adoc b/extensions/readme.adoc
index d864076..e5a6ea0 100644
--- a/extensions/readme.adoc
+++ b/extensions/readme.adoc
@@ -44,7 +44,7 @@
 | link:https://camel.apache.org/components/latest/mail-component.html[Mail] (camel-quarkus-mail) +
 `imap:host:port` | 0.2 | To send or receive emails using imap/pop3 or smtp protocols.
 
-| link:https://camel.apache.org/components/latest/microprofile-metrics-component.html[MicroProfile Metrics] (camel-quarkus-microprofile-metrics) +
+| xref:extensions/microprofile-metrics.adoc[MicroProfile Metrics] (camel-quarkus-microprofile-metrics) +
 `microprofile-metrics:metricType:metricName` | 0.2 | Camel metrics exposed with Eclipse MicroProfile Metrics
 
 | link:https://camel.apache.org/components/latest/netty-http-component.html[Netty HTTP] (camel-quarkus-netty-http) +
@@ -144,9 +144,9 @@
 
 | (camel-quarkus-reactive-executor) | 0.2.1 | To use Quarkus reactive executor with Camel
 
-| (camel-quarkus-microprofile-health) | 0.2.1 | Integration with the Quarkus MicroProfile Health extension
+| xref:extensions/microprofile-health.adoc[camel-quarkus-microprofile-health]  | 0.2.1 | Integration with the Quarkus MicroProfile Health extension
 
-| (camel-quarkus-opentracing) | 0.2.1 | Distributed tracing using OpenTracing
+| xref:extensions/opentracing.adoc[camel-quarkus-opentracing]  | 0.2.1 | Distributed tracing using OpenTracing
 |===
 // others: END
 
diff --git a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/UpdateDocExtensionsListMojo.java b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/UpdateDocExtensionsListMojo.java
index 705b8af..fbc058d 100644
--- a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/UpdateDocExtensionsListMojo.java
+++ b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/UpdateDocExtensionsListMojo.java
@@ -19,6 +19,8 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -95,6 +97,12 @@
     protected File readmeExtensionsDir;
 
     /**
+     * The website doc base directory
+     */
+    @Parameter(defaultValue = "${project.directory}/../../../docs/modules/ROOT/pages")
+    protected File websiteDocBaseDir;
+
+    /**
      * The website doc for extensions
      */
     @Parameter(defaultValue = "${project.directory}/../../../docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc")
@@ -660,6 +668,7 @@
         component.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
         component.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
         component.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        component.setExtensionsDocPath(getExtensionsDocPath());
 
         return component;
     }
@@ -680,6 +689,7 @@
         dataFormat.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
         dataFormat.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
         dataFormat.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        dataFormat.setExtensionsDocPath(getExtensionsDocPath());
 
         return dataFormat;
     }
@@ -700,6 +710,7 @@
         language.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
         language.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
         language.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        language.setExtensionsDocPath(getExtensionsDocPath());
 
         return language;
     }
@@ -718,8 +729,13 @@
         other.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
         other.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
         other.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        other.setExtensionsDocPath(getExtensionsDocPath());
 
         return other;
     }
 
+    private Path getExtensionsDocPath() {
+        return Paths.get(websiteDocBaseDir.toString(), "extensions");
+    }
+
 }
diff --git a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/AbstractModel.java b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/AbstractModel.java
new file mode 100644
index 0000000..aadcf82
--- /dev/null
+++ b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/AbstractModel.java
@@ -0,0 +1,184 @@
+/*
+ * 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.quarkus.maven.model;
+
+import java.nio.file.Path;
+
+import org.apache.camel.quarkus.maven.StringHelper;
+import static org.apache.camel.quarkus.maven.StringHelper.cutLastZeroDigit;
+
+public abstract class AbstractModel {
+
+    private String kind;
+    private String name;
+    private String modelName;
+    private String title;
+    private String description;
+    private String firstVersion;
+    private String label;
+    private String deprecated;
+    private String deprecationNote;
+    private String javaType;
+    private String groupId;
+    private String artifactId;
+    private String version;
+    private Path extensionsDocPath;
+
+    public String getKind() {
+        return kind;
+    }
+
+    public void setKind(String kind) {
+        this.kind = kind;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getModelName() {
+        return modelName;
+    }
+
+    public void setModelName(String modelName) {
+        this.modelName = modelName;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getFirstVersion() {
+        return firstVersion;
+    }
+
+    public void setFirstVersion(String firstVersion) {
+        this.firstVersion = firstVersion;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public String getDeprecated() {
+        return deprecated;
+    }
+
+    public void setDeprecated(String deprecated) {
+        this.deprecated = deprecated;
+    }
+
+    public String getDeprecationNote() {
+        return deprecationNote;
+    }
+
+    public void setDeprecationNote(String deprecationNote) {
+        this.deprecationNote = deprecationNote;
+    }
+
+    public String getJavaType() {
+        return javaType;
+    }
+
+    public void setJavaType(String javaType) {
+        this.javaType = javaType;
+    }
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getShortJavaType() {
+        return StringHelper.getClassShortName(javaType);
+    }
+
+    public boolean localDocExists() {
+        Path path = extensionsDocPath.resolve(getExtensionDocName());
+        return path.toFile().exists();
+    }
+
+    public Path getExtensionsDocPath() {
+        return extensionsDocPath;
+    }
+
+    public void setExtensionsDocPath(Path extensionsDocPath) {
+        this.extensionsDocPath = extensionsDocPath;
+    }
+
+    public String getLocalDocLink() {
+        return "xref:extensions/" + getExtensionDocName();
+    }
+
+    public String getExtensionDocName() {
+        return StringHelper.after(artifactId, "camel-quarkus-") + ".adoc";
+    }
+
+    public String getDocLink() {
+        if (localDocExists()) {
+            return getLocalDocLink();
+        }
+        return String.format("link:https://camel.apache.org/%s/latest/%s", getDocLinkSection(), getDocLinkDocument());
+    }
+
+    public String getFirstVersionShort() {
+        return cutLastZeroDigit(firstVersion);
+    }
+
+    abstract String getDocLinkSection();
+    abstract String getDocLinkDocument();
+
+}
diff --git a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/ComponentModel.java b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/ComponentModel.java
index fb9dda6..ca52b64 100644
--- a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/ComponentModel.java
+++ b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/ComponentModel.java
@@ -16,37 +16,14 @@
  */
 package org.apache.camel.quarkus.maven.model;
 
-import org.apache.camel.quarkus.maven.StringHelper;
+public class ComponentModel extends AbstractModel {
 
-import static org.apache.camel.quarkus.maven.StringHelper.cutLastZeroDigit;
-
-public class ComponentModel {
-
-    private String kind;
     private String scheme;
     private String syntax;
     private String alternativeSyntax;
     private String alternativeSchemes;
-    private String title;
-    private String description;
-    private String firstVersion;
-    private String label;
-    private String deprecated;
-    private String deprecationNote;
     private String consumerOnly;
     private String producerOnly;
-    private String javaType;
-    private String groupId;
-    private String artifactId;
-    private String version;
-
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
 
     public String getScheme() {
         return scheme;
@@ -80,54 +57,6 @@
         this.alternativeSchemes = alternativeSchemes;
     }
 
-    public String getTitle() {
-        return title;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public String getFirstVersion() {
-        return firstVersion;
-    }
-
-    public void setFirstVersion(String firstVersion) {
-        this.firstVersion = firstVersion;
-    }
-
-    public String getLabel() {
-        return label;
-    }
-
-    public void setLabel(String label) {
-        this.label = label;
-    }
-
-    public String getDeprecated() {
-        return deprecated;
-    }
-
-    public void setDeprecated(String deprecated) {
-        this.deprecated = deprecated;
-    }
-
-    public String getDeprecationNote() {
-        return deprecationNote;
-    }
-
-    public void setDeprecationNote(String deprecationNote) {
-        this.deprecationNote = deprecationNote;
-    }
-
     public String getConsumerOnly() {
         return consumerOnly;
     }
@@ -144,47 +73,14 @@
         this.producerOnly = producerOnly;
     }
 
-    public String getJavaType() {
-        return javaType;
+    @Override
+    String getDocLinkSection() {
+        return "components";
     }
 
-    public void setJavaType(String javaType) {
-        this.javaType = javaType;
+    @Override
+    String getDocLinkDocument() {
+        return scheme + "-component.html";
     }
 
-    public String getGroupId() {
-        return groupId;
-    }
-
-    public void setGroupId(String groupId) {
-        this.groupId = groupId;
-    }
-
-    public String getArtifactId() {
-        return artifactId;
-    }
-
-    public void setArtifactId(String artifactId) {
-        this.artifactId = artifactId;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
-    }
-
-    public String getDocLink() {
-        return "https://camel.apache.org/components/latest/" + scheme + "-component.html";
-    }
-
-    public String getFirstVersionShort() {
-        return cutLastZeroDigit(firstVersion);
-    }
 }
diff --git a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/DataFormatModel.java b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/DataFormatModel.java
index 340fa5c..16d83d2 100644
--- a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/DataFormatModel.java
+++ b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/DataFormatModel.java
@@ -16,140 +16,16 @@
  */
 package org.apache.camel.quarkus.maven.model;
 
-import org.apache.camel.quarkus.maven.StringHelper;
+public class DataFormatModel extends AbstractModel {
 
-import static org.apache.camel.quarkus.maven.StringHelper.cutLastZeroDigit;
-
-public class DataFormatModel {
-
-    private String kind;
-    private String name;
-    private String modelName;
-    private String title;
-    private String description;
-    private String firstVersion;
-    private String label;
-    private String deprecated;
-    private String deprecationNote;
-    private String javaType;
-    private String groupId;
-    private String artifactId;
-    private String version;
-
-    public String getKind() {
-        return kind;
+    @Override
+    String getDocLinkSection() {
+        return "components";
     }
 
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getModelName() {
-        return modelName;
-    }
-
-    public void setModelName(String modelName) {
-        this.modelName = modelName;
-    }
-
-    public String getTitle() {
-        return title;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public String getFirstVersion() {
-        return firstVersion;
-    }
-
-    public void setFirstVersion(String firstVersion) {
-        this.firstVersion = firstVersion;
-    }
-
-    public String getLabel() {
-        return label;
-    }
-
-    public void setLabel(String label) {
-        this.label = label;
-    }
-
-    public String getDeprecated() {
-        return deprecated;
-    }
-
-    public void setDeprecated(String deprecated) {
-        this.deprecated = deprecated;
-    }
-
-    public String getDeprecationNote() {
-        return deprecationNote;
-    }
-
-    public void setDeprecationNote(String deprecationNote) {
-        this.deprecationNote = deprecationNote;
-    }
-
-    public String getJavaType() {
-        return javaType;
-    }
-
-    public void setJavaType(String javaType) {
-        this.javaType = javaType;
-    }
-
-    public String getGroupId() {
-        return groupId;
-    }
-
-    public void setGroupId(String groupId) {
-        this.groupId = groupId;
-    }
-
-    public String getArtifactId() {
-        return artifactId;
-    }
-
-    public void setArtifactId(String artifactId) {
-        this.artifactId = artifactId;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
-    }
-
-    public String getDocLink() {
-        return "https://camel.apache.org/components/latest/" + name + "-dataformat.html";
-    }
-
-    public String getFirstVersionShort() {
-        return cutLastZeroDigit(firstVersion);
+    @Override
+    String getDocLinkDocument() {
+        return getName() + "-dataformat.html";
     }
 
 }
diff --git a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/LanguageModel.java b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/LanguageModel.java
index 9d3ea32..c72dfab 100644
--- a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/LanguageModel.java
+++ b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/LanguageModel.java
@@ -16,140 +16,16 @@
  */
 package org.apache.camel.quarkus.maven.model;
 
-import org.apache.camel.quarkus.maven.StringHelper;
+public class LanguageModel extends AbstractModel {
 
-import static org.apache.camel.quarkus.maven.StringHelper.cutLastZeroDigit;
-
-public class LanguageModel {
-
-    private String kind;
-    private String name;
-    private String modelName;
-    private String title;
-    private String description;
-    private String firstVersion;
-    private String label;
-    private String deprecated;
-    private String deprecationNote;
-    private String javaType;
-    private String groupId;
-    private String artifactId;
-    private String version;
-
-    public String getKind() {
-        return kind;
+    @Override
+    String getDocLinkSection() {
+        return "components";
     }
 
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getModelName() {
-        return modelName;
-    }
-
-    public void setModelName(String modelName) {
-        this.modelName = modelName;
-    }
-
-    public String getTitle() {
-        return title;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public String getFirstVersion() {
-        return firstVersion;
-    }
-
-    public void setFirstVersion(String firstVersion) {
-        this.firstVersion = firstVersion;
-    }
-
-    public String getLabel() {
-        return label;
-    }
-
-    public void setLabel(String label) {
-        this.label = label;
-    }
-
-    public String getDeprecated() {
-        return deprecated;
-    }
-
-    public void setDeprecated(String deprecated) {
-        this.deprecated = deprecated;
-    }
-
-    public String getDeprecationNote() {
-        return deprecationNote;
-    }
-
-    public void setDeprecationNote(String deprecationNote) {
-        this.deprecationNote = deprecationNote;
-    }
-
-    public String getJavaType() {
-        return javaType;
-    }
-
-    public void setJavaType(String javaType) {
-        this.javaType = javaType;
-    }
-
-    public String getGroupId() {
-        return groupId;
-    }
-
-    public void setGroupId(String groupId) {
-        this.groupId = groupId;
-    }
-
-    public String getArtifactId() {
-        return artifactId;
-    }
-
-    public void setArtifactId(String artifactId) {
-        this.artifactId = artifactId;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
-    }
-
-    public String getDocLink() {
-        return "https://camel.apache.org/components/latest/" + name + "-language.html";
-    }
-
-    public String getFirstVersionShort() {
-        return cutLastZeroDigit(firstVersion);
+    @Override
+    String getDocLinkDocument() {
+        return getName() + "-language.html";
     }
 
 }
diff --git a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/OtherModel.java b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/OtherModel.java
index 3ca3f55..ea213da 100644
--- a/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/OtherModel.java
+++ b/tooling/maven/package-maven-plugin/src/main/java/org/apache/camel/quarkus/maven/model/OtherModel.java
@@ -16,130 +16,19 @@
  */
 package org.apache.camel.quarkus.maven.model;
 
-import org.apache.camel.quarkus.maven.StringHelper;
-
-import static org.apache.camel.quarkus.maven.StringHelper.cutLastZeroDigit;
-
-public class OtherModel {
-
-    private String kind;
-    private String name;
-    private String title;
-    private String description;
-    private String firstVersion;
-    private String label;
-    private String deprecated;
-    private String deprecationNote;
-    private String groupId;
-    private String artifactId;
-    private String version;
-    private String javaType;
-
-    public String getJavaType() {
-        return javaType;
-    }
-
-    public void setJavaType(String javaType) {
-        this.javaType = javaType;
-    }
-
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getTitle() {
-        return title;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public String getFirstVersion() {
-        return firstVersion;
-    }
-
-    public void setFirstVersion(String firstVersion) {
-        this.firstVersion = firstVersion;
-    }
-
-    public String getLabel() {
-        return label;
-    }
-
-    public void setLabel(String label) {
-        this.label = label;
-    }
-
-    public String getDeprecated() {
-        return deprecated;
-    }
-
-    public void setDeprecated(String deprecated) {
-        this.deprecated = deprecated;
-    }
-
-    public String getDeprecationNote() {
-        return deprecationNote;
-    }
-
-    public void setDeprecationNote(String deprecationNote) {
-        this.deprecationNote = deprecationNote;
-    }
-
-    public String getGroupId() {
-        return groupId;
-    }
-
-    public void setGroupId(String groupId) {
-        this.groupId = groupId;
-    }
-
-    public String getArtifactId() {
-        return artifactId;
-    }
-
-    public void setArtifactId(String artifactId) {
-        this.artifactId = artifactId;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
+public class OtherModel extends AbstractModel {
 
     public String getDocLink() {
-        return "https://camel.apache.org/components/latest/" + name + ".html";
+        return localDocExists() ? getLocalDocLink() : null;
     }
 
-    public String getFirstVersionShort() {
-        return cutLastZeroDigit(firstVersion);
+    @Override
+    String getDocLinkSection() {
+        return null;
     }
 
-    public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+    @Override
+    String getDocLinkDocument() {
+        return null;
     }
 }
diff --git a/tooling/maven/package-maven-plugin/src/main/resources/readme-components.mvel b/tooling/maven/package-maven-plugin/src/main/resources/readme-components.mvel
index 3f21644..4904ef1 100644
--- a/tooling/maven/package-maven-plugin/src/main/resources/readme-components.mvel
+++ b/tooling/maven/package-maven-plugin/src/main/resources/readme-components.mvel
@@ -6,7 +6,7 @@
 |===
 | Component | Since | Description
 @foreach{row : components}
-| link:@{row.docLink}[@{row.title}] (@{row.artifactId}) +
+| @{row.docLink}[@{row.title}] (@{row.artifactId}) +
 `@{row.syntax}` | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}
 |===
diff --git a/tooling/maven/package-maven-plugin/src/main/resources/readme-dataformats.mvel b/tooling/maven/package-maven-plugin/src/main/resources/readme-dataformats.mvel
index d024aa4..e436114 100644
--- a/tooling/maven/package-maven-plugin/src/main/resources/readme-dataformats.mvel
+++ b/tooling/maven/package-maven-plugin/src/main/resources/readme-dataformats.mvel
@@ -6,7 +6,7 @@
 |===
 | Data Format | Since | Description
 @foreach{row : dataformats}
-| link:@{row.docLink}[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
+| @{row.docLink}[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}|===
 
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/package-maven-plugin/src/main/resources/readme-languages.mvel b/tooling/maven/package-maven-plugin/src/main/resources/readme-languages.mvel
index ec6f269..28df02b 100644
--- a/tooling/maven/package-maven-plugin/src/main/resources/readme-languages.mvel
+++ b/tooling/maven/package-maven-plugin/src/main/resources/readme-languages.mvel
@@ -6,7 +6,7 @@
 |===
 | Language | Since | Description
 @foreach{row : languages}
-| link:@{row.docLink}[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
+| @{row.docLink}[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}|===
 
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/package-maven-plugin/src/main/resources/readme-others.mvel b/tooling/maven/package-maven-plugin/src/main/resources/readme-others.mvel
index 5c5840d..e873d89 100644
--- a/tooling/maven/package-maven-plugin/src/main/resources/readme-others.mvel
+++ b/tooling/maven/package-maven-plugin/src/main/resources/readme-others.mvel
@@ -6,7 +6,7 @@
 |===
 | Extension | Since | Description
 @foreach{row : others}
-| (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
+|@if{row.docLink != null} @{row.docLink}[@{row.artifactId}] @else{} (@{row.artifactId})@end{} | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}|===
 
 @end{}
\ No newline at end of file