You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2020/01/15 16:12:08 UTC

[camel] 02/07: Move a few helper methods around, syntactic enhancements for streams, etc...

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c1a0f9fa0cd76c7ef41550fe475d57711c9c6899
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sat Dec 21 00:01:43 2019 +0100

    Move a few helper methods around, syntactic enhancements for streams, etc...
---
 bom/camel-bom/pom.xml                              |   5 +
 parent/pom.xml                                     |   5 +
 tooling/apt/pom.xml                                |   6 +-
 .../camel/tools/apt/AnnotationProcessorHelper.java |  35 +--
 .../camel/tools/apt/ConstantProviderProcessor.java |  12 +-
 .../apt/CoreEipAnnotationProcessorHelper.java      |  14 +-
 .../camel/tools/apt/DocumentationHelper.java       |   2 +-
 .../tools/apt/EndpointAnnotationProcessor.java     |  20 +-
 .../camel/tools/apt/ModelAnnotationProcessor.java  |   2 +-
 .../tools/apt/PropertyConfigurerGenerator.java     |  20 +-
 .../tools/apt/PropertyPlaceholderGenerator.java    |  19 +-
 .../org/apache/camel/tools/apt/SpiProcessor.java   |   2 +-
 .../tools/apt/SpringAnnotationProcessorHelper.java |  14 +-
 .../camel/tools/apt/TypeConverterProcessor.java    |   2 +-
 .../camel/tools/apt/helper/EndpointHelper.java     |   1 +
 .../apache/camel/tools/apt/helper/IOHelper.java    |  84 ------
 .../org/apache/camel/tools/apt/helper/Strings.java | 144 ---------
 .../camel/tools/apt/model/ComponentOption.java     |   2 +-
 .../camel/tools/apt/model/EndpointOption.java      |   2 +-
 tooling/camel-tooling-util/pom.xml                 |  45 +++
 .../org/apache/camel/tooling/util/FileUtil.java    |  81 +++++
 .../camel/tooling/util/JSonSchemaHelper.java}      | 153 ++++++++--
 .../apache/camel/tooling/util}/PackageHelper.java  |  99 +++----
 .../org/apache/camel/tooling/util/Strings.java     | 328 +++++++++++++++++++++
 .../src/main/resources/META-INF/LICENSE.txt        | 203 +++++++++++++
 .../src/main/resources/META-INF/NOTICE.txt         |  14 +
 .../camel/tooling/util/JSonSchemaHelperTest.java}  |  12 +-
 .../camel/tooling/util}/PackageHelperTest.java     |   3 +-
 .../apache/camel/tooling/util/ResourceUtils.java}  |  23 +-
 .../org/apache/camel/tooling/util/StringsTest.java |  40 +++
 .../src/test/resources/filecontent/a.txt           |   0
 .../src/test/resources/json/a.json                 |   0
 .../src/test/resources/json/aop.json               |   0
 .../src/test/resources/json/b.json                 |   0
 .../src/test/resources/json/c.txt                  |   0
 tooling/maven/bom-generator-maven-plugin/pom.xml   |   4 +
 .../maven/bom/generator/BomGeneratorMojo.java      |  41 +--
 .../maven/camel-api-component-maven-plugin/pom.xml |   5 +
 .../apache/camel/maven/AbstractGeneratorMojo.java  |  22 +-
 .../pom.xml                                        |   8 +
 .../apache/camel/maven/DocumentationEnricher.java  |   1 +
 .../camel/maven/EipDocumentationEnricherMojo.java  |   1 +
 .../java/org/apache/camel/maven/PackageHelper.java |  68 -----
 .../maven/camel-main-package-maven-plugin/pom.xml  |   5 +
 .../apache/camel/maven/PrepareCamelMainMojo.java   |  32 +-
 tooling/maven/camel-package-maven-plugin/pom.xml   |   5 +-
 .../maven/packaging/AbstractGeneratorMojo.java     |  44 +--
 .../camel/maven/packaging/EndpointDslMojo.java     |  46 ++-
 .../camel/maven/packaging/JSonSchemaHelper.java    | 206 -------------
 .../packaging/PackageArchetypeCatalogMojo.java     |   6 +-
 .../maven/packaging/PackageComponentMojo.java      |  13 +-
 .../maven/packaging/PackageDataFormatMojo.java     |  23 +-
 .../camel/maven/packaging/PackageLanguageMojo.java |  19 +-
 .../camel/maven/packaging/PackageModelMojo.java    |   1 +
 .../camel/maven/packaging/PackageOtherMojo.java    |   2 +-
 .../maven/packaging/PrepareCatalogKarafMojo.java   | 264 +++++------------
 .../camel/maven/packaging/PrepareCatalogMojo.java  | 251 ++++------------
 .../camel/maven/packaging/PrepareExampleMojo.java  |  26 +-
 .../maven/packaging/PrepareParentPomMojo.java      |  18 +-
 .../maven/packaging/PrepareReleasePomMojo.java     |  20 +-
 .../maven/packaging/PrepareUserGuideMojo.java      | 159 +++++-----
 .../apache/camel/maven/packaging/StringHelper.java | 200 -------------
 .../packaging/UpdateDocComponentListMojo.java      | 225 +++++++-------
 .../camel/maven/packaging/UpdateReadmeMojo.java    |  68 ++---
 .../maven/packaging/ValidateComponentMojo.java     |  10 +-
 .../camel/maven/packaging/ValidateHelper.java      |  14 +-
 .../maven/packaging/model/ComponentModel.java      |   6 +-
 .../packaging/model/ComponentOptionModel.java      |   8 +-
 .../maven/packaging/model/DataFormatModel.java     |   6 +-
 .../packaging/model/DataFormatOptionModel.java     |   4 +-
 .../maven/packaging/model/EipOptionModel.java      |   8 +-
 .../maven/packaging/model/EndpointOptionModel.java |   8 +-
 .../camel/maven/packaging/model/LanguageModel.java |   6 +-
 .../maven/packaging/model/LanguageOptionModel.java |   4 +-
 .../camel/maven/packaging/model/OtherModel.java    |   6 +-
 .../maven/packaging/model/OtherOptionModel.java    |   8 +-
 .../model/SpringBootAutoConfigureOptionModel.java  |   8 +-
 .../src/main/resources/component-options.mvel      |   2 +-
 .../maven/packaging/model/StringHelperTest.java    |   4 +-
 tooling/pom.xml                                    |   1 +
 80 files changed, 1514 insertions(+), 1764 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index a639b8e..3469331 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -1690,6 +1690,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-tooling-util</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-twilio</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/parent/pom.xml b/parent/pom.xml
index a1dd9c6..6c8ce08 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -731,6 +731,11 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
+                <artifactId>camel-tooling-util</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
                 <artifactId>camel-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/tooling/apt/pom.xml b/tooling/apt/pom.xml
index 8c3347d..2a81ce2 100644
--- a/tooling/apt/pom.xml
+++ b/tooling/apt/pom.xml
@@ -46,14 +46,16 @@
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>spi-annotations</artifactId>
-            <version>${project.version}</version>
         </dependency>
 
         <!-- use our patched ordered json-simple parser -->
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-util-json</artifactId>
-            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-util</artifactId>
         </dependency>
 
         <!-- logging -->
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java
index 4b824ad..a938f08 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java
@@ -18,7 +18,6 @@ package org.apache.camel.tools.apt;
 
 import java.io.BufferedWriter;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
@@ -46,9 +45,8 @@ import javax.tools.Diagnostic;
 import javax.tools.FileObject;
 import javax.tools.StandardLocation;
 
-import static org.apache.camel.tools.apt.helper.IOHelper.loadText;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.isNullOrEmpty;
 
 /**
  * Abstract class for Camel apt plugins.
@@ -338,10 +336,6 @@ public final class AnnotationProcessorHelper {
         processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
     }
 
-    public static void warning(ProcessingEnvironment processingEnv, String message) {
-        processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, message);
-    }
-
     public static void error(ProcessingEnvironment processingEnv, String message) {
         processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
     }
@@ -355,31 +349,6 @@ public final class AnnotationProcessorHelper {
         processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, buffer.toString());
     }
 
-    public static String loadResource(ProcessingEnvironment processingEnv, String packageName, String fileName) {
-        Filer filer = processingEnv.getFiler();
-
-        FileObject resource;
-        String relativeName = packageName + "/" + fileName;
-        try {
-            resource = filer.getResource(StandardLocation.CLASS_OUTPUT, "", relativeName);
-        } catch (Throwable e) {
-            return "Cannot load classpath resource: " + relativeName + " due: " + e.getMessage();
-        }
-
-        if (resource == null) {
-            return null;
-        }
-
-        try {
-            InputStream is = resource.openInputStream();
-            return loadText(is, true);
-        } catch (Exception e) {
-            warning(processingEnv, "APT cannot load file: " + packageName + "/" + fileName);
-        }
-
-        return null;
-    }
-
     public static void dumpExceptionToErrorFile(String fileName, String message, Throwable e) {
         try (BufferedWriter w = Files.newBufferedWriter(Paths.get(fileName), StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
             w.append(message);
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConstantProviderProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConstantProviderProcessor.java
index 749fbb0..2066e10 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConstantProviderProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConstantProviderProcessor.java
@@ -30,13 +30,11 @@ import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.ElementFilter;
 import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
 
 import org.apache.camel.spi.annotations.ConstantProvider;
-import org.apache.camel.tools.apt.helper.IOHelper;
 
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
 
 @SupportedAnnotationTypes({"org.apache.camel.spi.annotations.ConstantProvider"})
 public class ConstantProviderProcessor extends AbstractCamelAnnotationProcessor {
@@ -89,11 +87,7 @@ public class ConstantProviderProcessor extends AbstractCamelAnnotationProcessor
         String pn = fqn.substring(0, fqn.lastIndexOf('.'));
         String cn = fqn.substring(fqn.lastIndexOf('.') + 1);
 
-        Writer w = null;
-        try {
-            JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn);
-            w = src.openWriter();
-
+        try (Writer w = processingEnv.getFiler().createSourceFile(fqn).openWriter()) {
             w.write("/* Generated by org.apache.camel:apt */\n");
             w.write("package " + pn + ";\n");
             w.write("\n");
@@ -122,8 +116,6 @@ public class ConstantProviderProcessor extends AbstractCamelAnnotationProcessor
         } catch (Exception e) {
             processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage());
             dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e);
-        } finally {
-            IOHelper.close(w);
         }
     }
 
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java
index 18a33c3..4eeea7d 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java
@@ -44,8 +44,8 @@ import javax.xml.bind.annotation.XmlValue;
 
 import org.apache.camel.spi.AsPredicate;
 import org.apache.camel.spi.Metadata;
-import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
-import org.apache.camel.tools.apt.helper.Strings;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
+import org.apache.camel.tooling.util.Strings;
 
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findJavaDoc;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement;
@@ -53,10 +53,10 @@ import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeEleme
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.hasSuperClass;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.implementsInterface;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile;
-import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
-import static org.apache.camel.tools.apt.helper.Strings.safeNull;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.sanitizeDescription;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.isNullOrEmpty;
+import static org.apache.camel.tooling.util.Strings.safeNull;
 
 /**
  * Process all camel-core's model classes (EIPs and DSL) and generate json
@@ -236,7 +236,7 @@ public class CoreEipAnnotationProcessorHelper {
             // as its json we need to sanitize the docs
             String doc = entry.getDocumentation();
             doc = sanitizeDescription(doc, false);
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
+            buffer.append(JSonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
                                                   entry.isDeprecated(), entry.getDeprecationNote(), false, null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(),
                                                   entry.getOneOfTypes(), entry.isAsPredicate(), null, null, false, null, null));
         }
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java
index fb243e3..a94b585 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java
@@ -22,7 +22,7 @@ import java.nio.file.Files;
 import java.util.List;
 import java.util.Map;
 
-import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.parseJsonSchema;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.parseJsonSchema;
 
 /**
  * Helper to find documentation for inherited options when a component extends another.
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
index 4f18719..0c08d6d 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
@@ -50,8 +50,8 @@ import org.apache.camel.spi.UriParams;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.spi.annotations.Component;
 import org.apache.camel.tools.apt.helper.EndpointHelper;
-import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
-import org.apache.camel.tools.apt.helper.Strings;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
+import org.apache.camel.tooling.util.Strings;
 import org.apache.camel.tools.apt.model.ComponentModel;
 import org.apache.camel.tools.apt.model.ComponentOption;
 import org.apache.camel.tools.apt.model.EndpointOption;
@@ -65,10 +65,10 @@ import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findJavaDoc;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.implementsInterface;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile;
-import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.helper.Strings.getOrElse;
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.sanitizeDescription;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.getOrElse;
+import static org.apache.camel.tooling.util.Strings.isNullOrEmpty;
 
 /**
  * Processes all Camel {@link UriEndpoint}s and generate json schema documentation for the endpoint/component.
@@ -326,7 +326,7 @@ public class EndpointAnnotationProcessor extends AbstractCamelAnnotationProcesso
             boolean multiValue = false;
             boolean asPredicate = false;
 
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), "property", required, entry.getType(), defaultValue, doc,
+            buffer.append(JSonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), "property", required, entry.getType(), defaultValue, doc,
                 entry.isDeprecated(), entry.getDeprecationNote(), entry.isSecret(), entry.getGroup(), entry.getLabel(), entry.isEnumType(), entry.getEnums(),
                 false, null, asPredicate, optionalPrefix, prefix, multiValue, entry.getConfigurationClass(), entry.getConfigurationField()));
 
@@ -400,7 +400,7 @@ public class EndpointAnnotationProcessor extends AbstractCamelAnnotationProcesso
             boolean multiValue = false;
             boolean asPredicate = false;
 
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), "path", required, entry.getType(), defaultValue, doc,
+            buffer.append(JSonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), "path", required, entry.getType(), defaultValue, doc,
                 entry.isDeprecated(), entry.getDeprecationNote(), entry.isSecret(), entry.getGroup(), entry.getLabel(), entry.isEnumType(), entry.getEnums(),
                 false, null, asPredicate, optionalPrefix, prefix, multiValue, null, null));
 
@@ -448,7 +448,7 @@ public class EndpointAnnotationProcessor extends AbstractCamelAnnotationProcesso
             boolean multiValue = entry.isMultiValue();
             boolean asPredicate = false;
 
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), "parameter", required, entry.getType(), defaultValue,
+            buffer.append(JSonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), "parameter", required, entry.getType(), defaultValue,
                 doc, entry.isDeprecated(), entry.getDeprecationNote(), entry.isSecret(), entry.getGroup(), entry.getLabel(), entry.isEnumType(), entry.getEnums(),
                 false, null, asPredicate, optionalPrefix, prefix, multiValue, entry.getConfigurationClass(), entry.getConfigurationField()));
 
@@ -765,7 +765,7 @@ public class EndpointAnnotationProcessor extends AbstractCamelAnnotationProcesso
                         isEnum = true;
                         String[] values = path.enums().split(",");
                         for (String val : values) {
-                            enums.add(val);
+                            enums.add(val.trim());
                         }
                     } else {
                         isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java
index 0995240..4d4528d 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java
@@ -30,7 +30,7 @@ import javax.lang.model.element.TypeElement;
 import javax.tools.Diagnostic.Kind;
 import javax.xml.bind.annotation.XmlRootElement;
 
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
 
 /**
  * APT compiler plugin to generate JSon Schema for all EIP models and camel-spring's <camelContext> types.
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyConfigurerGenerator.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyConfigurerGenerator.java
index 6c8af09..3ab11c9 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyConfigurerGenerator.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyConfigurerGenerator.java
@@ -24,10 +24,8 @@ import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.TypeElement;
 import javax.tools.Diagnostic;
 import javax.tools.FileObject;
-import javax.tools.JavaFileObject;
 import javax.tools.StandardLocation;
 
-import org.apache.camel.tools.apt.helper.IOHelper;
 import org.apache.camel.tools.apt.model.PropertyOption;
 
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile;
@@ -40,11 +38,7 @@ public final class PropertyConfigurerGenerator {
     public static void generateExtendConfigurer(ProcessingEnvironment processingEnv, TypeElement parent,
                                                 String pn, String cn, String fqn) {
 
-        Writer w = null;
-        try {
-            JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn, parent);
-            w = src.openWriter();
-
+        try (Writer w = processingEnv.getFiler().createSourceFile(fqn, parent).openWriter()) {
             w.write("/* Generated by org.apache.camel:apt */\n");
             w.write("package " + pn + ";\n");
             w.write("\n");
@@ -60,8 +54,6 @@ public final class PropertyConfigurerGenerator {
         } catch (Exception e) {
             processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage());
             dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e);
-        } finally {
-            IOHelper.close(w);
         }
     }
 
@@ -69,13 +61,7 @@ public final class PropertyConfigurerGenerator {
                                                   String pn, String cn, String fqn, String en,
                                                   Set<PropertyOption> options) {
 
-        Writer w = null;
-        try {
-            JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn, parent);
-            w = src.openWriter();
-
-            int size = options.size();
-
+        try (Writer w = processingEnv.getFiler().createSourceFile(fqn, parent).openWriter()) {
             w.write("/* Generated by org.apache.camel:apt */\n");
             w.write("package " + pn + ";\n");
             w.write("\n");
@@ -130,8 +116,6 @@ public final class PropertyConfigurerGenerator {
         } catch (Exception e) {
             processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage());
             dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e);
-        } finally {
-            IOHelper.close(w);
         }
     }
 
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyPlaceholderGenerator.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyPlaceholderGenerator.java
index 85e5000..556c5de 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyPlaceholderGenerator.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyPlaceholderGenerator.java
@@ -23,9 +23,6 @@ import javax.annotation.processing.ProcessingEnvironment;
 import javax.annotation.processing.RoundEnvironment;
 import javax.lang.model.element.TypeElement;
 import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-
-import org.apache.camel.tools.apt.helper.IOHelper;
 
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile;
 
@@ -38,11 +35,7 @@ public final class PropertyPlaceholderGenerator {
                                                                  String def, String fqnDef, String cn, String fqn,
                                                                  Set<CoreEipAnnotationProcessorHelper.EipOption> options) {
 
-        Writer w = null;
-        try {
-            JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn, parent);
-            w = src.openWriter();
-
+        try (Writer w = processingEnv.getFiler().createSourceFile(fqn, parent).openWriter()) {
             w.write("/* Generated by org.apache.camel:apt */\n");
             w.write("package org.apache.camel.model.placeholder;\n");
             w.write("\n");
@@ -101,8 +94,6 @@ public final class PropertyPlaceholderGenerator {
         } catch (Exception e) {
             processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage());
             dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e);
-        } finally {
-            IOHelper.close(w);
         }
     }
 
@@ -111,11 +102,7 @@ public final class PropertyPlaceholderGenerator {
 
         String fqn = "org.apache.camel.model.placeholder.DefinitionPropertiesPlaceholderProviderHelper";
 
-        Writer w = null;
-        try {
-            JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn);
-            w = src.openWriter();
-
+        try (Writer w = processingEnv.getFiler().createSourceFile(fqn).openWriter()) {
             w.write("/* Generated by camel-apt */\n");
             w.write("package org.apache.camel.model.placeholder;\n");
             w.write("\n");
@@ -158,8 +145,6 @@ public final class PropertyPlaceholderGenerator {
         } catch (Exception e) {
             processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage());
             dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e);
-        } finally {
-            IOHelper.close(w);
         }
     }
 
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpiProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpiProcessor.java
index 28cec75..dc97f87 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpiProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpiProcessor.java
@@ -30,7 +30,7 @@ import javax.tools.StandardLocation;
 import org.apache.camel.spi.annotations.ServiceFactory;
 import org.apache.camel.spi.annotations.SubServiceFactory;
 
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
 
 @SupportedAnnotationTypes({"org.apache.camel.spi.annotations.*"})
 public class SpiProcessor extends AbstractCamelAnnotationProcessor {
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java
index 7259f47..e925af8 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java
@@ -40,16 +40,16 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 
 import org.apache.camel.spi.Metadata;
-import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
-import org.apache.camel.tools.apt.helper.Strings;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
+import org.apache.camel.tooling.util.Strings;
 
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findJavaDoc;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement;
 import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile;
-import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
-import static org.apache.camel.tools.apt.helper.Strings.safeNull;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.sanitizeDescription;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.isNullOrEmpty;
+import static org.apache.camel.tooling.util.Strings.safeNull;
 
 /**
  * Process camel-spring's <camelContext> and generate json schema documentation
@@ -137,7 +137,7 @@ public class SpringAnnotationProcessorHelper {
             String doc = entry.getDocumentation();
             doc = sanitizeDescription(doc, false);
 
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
+            buffer.append(JSonSchemaHelper.toJson(entry.getName(), entry.getDisplayName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
                                                   entry.isDeprecated(), entry.getDeprecationNote(), false, null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(),
                                                   entry.getOneOfTypes(), entry.isAsPredicate(), null, null, false, null, null));
         }
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/TypeConverterProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/TypeConverterProcessor.java
index d4d1ae9..4d64b86 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/TypeConverterProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/TypeConverterProcessor.java
@@ -32,7 +32,7 @@ import javax.lang.model.element.TypeElement;
 import javax.tools.FileObject;
 import javax.tools.StandardLocation;
 
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+import static org.apache.camel.tooling.util.Strings.canonicalClassName;
 
 @SupportedAnnotationTypes({"org.apache.camel.Converter"})
 public class TypeConverterProcessor extends AbstractCamelAnnotationProcessor {
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java
index bf07850..a51fc92 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java
@@ -18,6 +18,7 @@ package org.apache.camel.tools.apt.helper;
 
 import java.util.Comparator;
 
+import org.apache.camel.tooling.util.Strings;
 import org.apache.camel.tools.apt.model.EndpointOption;
 import org.apache.camel.tools.apt.model.EndpointPath;
 
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/IOHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/IOHelper.java
deleted file mode 100644
index bc95e31..0000000
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/IOHelper.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.tools.apt.helper;
-
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-
-public final class IOHelper {
-
-    private IOHelper() {
-    }
-
-    /**
-     * Loads the entire stream into memory as a String and returns it.
-     * <p/>
-     * <b>Notice:</b> This implementation appends a <tt>\n</tt> as line
-     * terminator at the of the text.
-     * <p/>
-     * Warning, don't use for crazy big streams :)
-     */
-    public static String loadText(InputStream in, boolean skipCommentOrEmptyLines) throws IOException {
-        StringBuilder builder = new StringBuilder();
-        InputStreamReader isr = new InputStreamReader(in);
-        try {
-            BufferedReader reader = new BufferedReader(isr);
-            while (true) {
-                String line = reader.readLine();
-                if (line != null) {
-
-                    boolean empty = Strings.isNullOrEmpty(line);
-                    boolean comment = line.trim().startsWith("#");
-                    if (skipCommentOrEmptyLines && (empty || comment)) {
-                        continue;
-                    }
-
-                    builder.append(line);
-                    builder.append("\n");
-                } else {
-                    break;
-                }
-            }
-            return builder.toString();
-        } finally {
-            close(isr, in);
-        }
-    }
-
-    /**
-     * Closes the given resources if they are available.
-     *
-     * @param closeables the objects to close
-     */
-    public static void close(Closeable... closeables) {
-        for (Closeable closeable : closeables) {
-            try {
-                if (closeable != null) {
-                    closeable.close();
-                }
-            } catch (IOException e) {
-                // ignore
-            }
-        }
-    }
-
-
-
-}
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/Strings.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/Strings.java
deleted file mode 100644
index aff3f45..0000000
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/Strings.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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.tools.apt.helper;
-
-/**
- * Some String helper methods
- */
-public final class Strings {
-
-    private Strings() {
-        //Helper class
-    }
-
-    /**
-     * Returns true if the given text is null or empty string or has <tt>null</tt> as the value
-     */
-    public static boolean isNullOrEmpty(String text) {
-        return text == null || text.length() == 0 || "null".equals(text);
-    }
-
-    public static String safeNull(String text) {
-        if (isNullOrEmpty(text)) {
-            return "";
-        } else {
-            return text;
-        }
-    }
-
-    /**
-     * Returns the value or the defaultValue if it is null
-     */
-    public static String getOrElse(String text, String defaultValue) {
-        return (text != null) ? text : defaultValue;
-    }
-
-    /**
-     * Returns the string after the given token
-     *
-     * @param text  the text
-     * @param after the token
-     * @return the text after the token, or <tt>null</tt> if text does not contain the token
-     */
-    public static String after(String text, String after) {
-        if (!text.contains(after)) {
-            return null;
-        }
-        return text.substring(text.indexOf(after) + after.length());
-    }
-
-    /**
-     * Returns the canonical class name by removing any generic type information.
-     */
-    public static String canonicalClassName(String className) {
-        // remove generics
-        int pos = className.indexOf('<');
-        if (pos != -1) {
-            return className.substring(0, pos);
-        } else {
-            return className;
-        }
-    }
-
-    /**
-     * Returns the text wrapped double quotes
-     */
-    public static String doubleQuote(String text) {
-        return quote(text, "\"");
-    }
-
-    /**
-     * Returns the text wrapped single quotes
-     */
-    public static String singleQuote(String text) {
-        return quote(text, "'");
-    }
-
-    /**
-     * Wraps the text in the given quote text
-     *
-     * @param text the text to wrap in quotes
-     * @param quote the quote text added to the prefix and postfix of the text
-     *
-     * @return the text wrapped in the given quotes
-     */
-    public static String quote(String text, String quote) {
-        return quote + text + quote;
-    }
-
-    /**
-     * Clips the text between the start and end markers
-     */
-    public static String between(String text, String start, String end) {
-        int pos = text.indexOf(start);
-        if (pos > 0) {
-            text = text.substring(pos + 1);
-        }
-        int pos2 = text.lastIndexOf(end);
-        if (pos2 > 0) {
-            text = text.substring(0, pos2);
-        }
-        return text;
-    }
-
-    /**
-     * Capitalizes the name as a title
-     *
-     * @param name  the name
-     * @return as a title
-     */
-    public static String asTitle(String name) {
-        StringBuilder sb = new StringBuilder();
-        for (char c : name.toCharArray()) {
-            boolean upper = Character.isUpperCase(c);
-            boolean first = sb.length() == 0;
-            if (first) {
-                sb.append(Character.toUpperCase(c));
-            } else if (upper) {
-                char prev = sb.charAt(sb.length() - 1);
-                if (!Character.isUpperCase(prev)) {
-                    // append space if previous is not upper
-                    sb.append(' ');
-                }
-                sb.append(c);
-            } else {
-                sb.append(Character.toLowerCase(c));
-            }
-        }
-        return sb.toString().trim();
-    }
-}
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentOption.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentOption.java
index dd77337..efec802 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentOption.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentOption.java
@@ -18,7 +18,7 @@ package org.apache.camel.tools.apt.model;
 
 import java.util.Set;
 
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
+import static org.apache.camel.tooling.util.Strings.isNullOrEmpty;
 
 public final class ComponentOption implements PropertyOption {
 
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/EndpointOption.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/EndpointOption.java
index c44ef4f..ff1a4c9 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/EndpointOption.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/EndpointOption.java
@@ -18,7 +18,7 @@ package org.apache.camel.tools.apt.model;
 
 import java.util.Set;
 
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
+import static org.apache.camel.tooling.util.Strings.isNullOrEmpty;
 
 public final class EndpointOption implements PropertyOption {
 
diff --git a/tooling/camel-tooling-util/pom.xml b/tooling/camel-tooling-util/pom.xml
new file mode 100644
index 0000000..d565914
--- /dev/null
+++ b/tooling/camel-tooling-util/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<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>org.apache.camel</groupId>
+        <artifactId>tooling</artifactId>
+        <version>3.1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-tooling-util</artifactId>
+
+    <name>Camel :: Tooling :: Util</name>
+    <description>Tooling utilities</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-util-json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/FileUtil.java b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/FileUtil.java
new file mode 100644
index 0000000..b39b552
--- /dev/null
+++ b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/FileUtil.java
@@ -0,0 +1,81 @@
+package org.apache.camel.tooling.util;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+
+public class FileUtil {
+
+    /**
+     * Update a file with the given string content if neeed.
+     * The file won't be modified if the content is already the same.
+     *
+     * @param path the path of the file to update
+     * @param newdata the new string data, <code>null</code> to delete the file
+     * @return <code>true</code> if the file was modified, <code>false</code> otherwise
+     * @throws IOException if an exception occurs
+     */
+    public static boolean updateFile(Path path, String newdata) throws IOException {
+        return updateFile(path, newdata != null ? newdata.getBytes() : null);
+    }
+
+    /**
+     * Update a file with the given string content if neeed.
+     * The file won't be modified if the content is already the same.
+     *
+     * @param path the path of the file to update
+     * @param newdata the new string data, <code>null</code> to delete the file
+     * @param encoding the encoding to use
+     * @return <code>true</code> if the file was modified, <code>false</code> otherwise
+     * @throws IOException if an exception occurs
+     */
+    public static boolean updateFile(Path path, String newdata, Charset encoding) throws IOException {
+        return updateFile(path, newdata != null ? newdata.getBytes(encoding) : null);
+    }
+
+    /**
+     * Update a file with the given binary content if neeed.
+     * The file won't be modified if the content is already the same.
+     *
+     * @param path the path of the file to update
+     * @param newdata the new binary data, <code>null</code> to delete the file
+     * @return <code>true</code> if the file was modified, <code>false</code> otherwise
+     * @throws IOException if an exception occurs
+     */
+    public static boolean updateFile(Path path, byte[] newdata) throws IOException {
+        if (newdata == null) {
+            if (!Files.exists(path)) {
+                return false;
+            }
+            Files.delete(path);
+            return true;
+        } else {
+            byte[] olddata = new byte[0];
+            if (Files.exists(path) && Files.isReadable(path)) {
+                olddata = Files.readAllBytes(path);
+            }
+            if (Arrays.equals(olddata, newdata)) {
+                return false;
+            }
+            Files.createDirectories(path.getParent());
+            Files.write(path, newdata, StandardOpenOption.WRITE,
+                    StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+            return true;
+        }
+    }
+
+    /**
+     * Read the content of the input file and update the target accordingly
+     *
+     * @param from the source file
+     * @param to the target file
+     * @throws IOException if an exception occurs
+     */
+    public static void updateFile(Path from, Path to) throws IOException {
+        updateFile(to, Files.readAllBytes(from));
+    }
+
+}
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/JSonSchemaHelper.java
similarity index 80%
rename from tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java
rename to tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/JSonSchemaHelper.java
index b4619ff..c03ef7c 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java
+++ b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/JSonSchemaHelper.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.tools.apt.helper;
+package org.apache.camel.tooling.util;
 
 import java.io.File;
 import java.net.URI;
@@ -33,18 +33,18 @@ import org.apache.camel.util.json.Jsoner;
 /**
  * A helper class for <a href="http://json-schema.org/">JSON schema</a>.
  */
-public final class JsonSchemaHelper {
+public final class JSonSchemaHelper {
 
     private static final String VALID_CHARS = ".,-='/\\!&%():;#${}";
 
-    private JsonSchemaHelper() {
+    private JSonSchemaHelper() {
     }
 
     public static String toJson(String name, String displayName, String kind, Boolean required, String type, String defaultValue, String description,
                                 Boolean deprecated, String deprecationNote, Boolean secret, String group, String label, boolean enumType, Set<String> enums,
                                 boolean oneOfType, Set<String> oneOffTypes, boolean asPredicate, String optionalPrefix, String prefix, boolean multiValue,
                                 String configurationClass, String configurationField) {
-        String typeName = JsonSchemaHelper.getType(type, enumType);
+        String typeName = JSonSchemaHelper.getType(type, enumType);
 
         StringBuilder sb = new StringBuilder();
         sb.append(Strings.doubleQuote(name));
@@ -79,7 +79,7 @@ public final class JsonSchemaHelper {
 
         sb.append(", \"type\": ");
         if ("enum".equals(typeName)) {
-            String actualType = JsonSchemaHelper.getType(type, false);
+            String actualType = JSonSchemaHelper.getType(type, false);
             sb.append(Strings.doubleQuote(actualType));
             sb.append(", \"javaType\": \"").append(type).append("\"");
             sb.append(", \"enum\": [ ");
@@ -349,24 +349,24 @@ public final class JsonSchemaHelper {
         try {
             JsonObject output = (JsonObject) Jsoner.deserialize(json);
             for (String key : output.keySet()) {
-                Map row = output.getMap(key);
+                Map<?, ?> row = output.getMap(key);
                 if (key.equals(group)) {
                     if (parseProperties) {
                         // flattern each entry in the row with name as they key, and its value as the content (its a map also)
                         for (Object obj : row.entrySet()) {
-                            Map.Entry entry = (Map.Entry) obj;
-                            Map<String, String> newRow = new LinkedHashMap();
+                            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
+                            Map<String, String> newRow = new LinkedHashMap<>();
                             newRow.put("name", entry.getKey().toString());
 
-                            Map newData = transformMap((Map) entry.getValue());
+                            Map<String, String> newData = transformMap((Map<?, ?>) entry.getValue());
                             newRow.putAll(newData);
                             answer.add(newRow);
                         }
                     } else {
                         // flattern each entry in the row as a list of single Map<key, value> elements
-                        Map newData = transformMap(row);
+                        Map<?, ?> newData = transformMap(row);
                         for (Object obj : newData.entrySet()) {
-                            Map.Entry entry = (Map.Entry) obj;
+                            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
                             Map<String, String> newRow = new LinkedHashMap<>();
                             newRow.put(entry.getKey().toString(), entry.getValue().toString());
                             answer.add(newRow);
@@ -382,17 +382,41 @@ public final class JsonSchemaHelper {
         return answer;
     }
 
-    private static Map<String, String> transformMap(Map jsonMap) {
+    private static String escapeJson(String value) {
+        // need to safe encode \r as \\r so its escaped
+        // need to safe encode \n as \\n so its escaped
+        // need to safe encode \t as \\t so its escaped
+        return value
+            .replaceAll("\\\\r", "\\\\\\r")
+            .replaceAll("\\\\n", "\\\\\\n")
+            .replaceAll("\\\\t", "\\\\\\t");
+    }
+
+    /**
+     * The default value may need to be escaped to be safe for json
+     */
+    private static String safeDefaultValue(String value) {
+        if ("\"".equals(value)) {
+            return "\\\"";
+        } else if ("\\".equals(value)) {
+            return "\\\\";
+        } else {
+            return value;
+        }
+    }
+
+    private static Map<String, String> transformMap(Map<?, ?> jsonMap) {
         Map<String, String> answer = new LinkedHashMap<>();
 
         for (Object rowObj : jsonMap.entrySet()) {
-            Map.Entry rowEntry = (Map.Entry) rowObj;
+            Map.Entry<?, ?> rowEntry = (Map.Entry<?, ?>) rowObj;
             // if its a list type then its an enum, and we need to parse it as a single line separated with comma
             // to be backwards compatible
             Object newValue = rowEntry.getValue();
             if (newValue instanceof List) {
-                List<Object> list = (List) newValue;
-                newValue = list.stream().map(String::valueOf).collect(Collectors.joining(","));
+                List<?> list = (List<?>) newValue;
+                newValue = list.stream().map(Object::toString)
+                        .collect(Collectors.joining(","));
             }
             // ensure value is escaped
             String value = escapeJson(newValue.toString());
@@ -402,27 +426,96 @@ public final class JsonSchemaHelper {
         return answer;
     }
 
-    private static String escapeJson(String value) {
-        // need to safe encode \r as \\r so its escaped
-        // need to safe encode \n as \\n so its escaped
-        // need to safe encode \t as \\t so its escaped
-        return value
-            .replaceAll("\\\\r", "\\\\\\r")
-            .replaceAll("\\\\n", "\\\\\\n")
-            .replaceAll("\\\\t", "\\\\\\t");
+    /**
+     * Gets the value with the key in a safe way, eg returning an empty string if there was no value for the key.
+     */
+    public static String getSafeValue(String key, List<Map<String, String>> rows) {
+        for (Map<String, String> row : rows) {
+            String value = row.get(key);
+            if (value != null) {
+                return value;
+            }
+        }
+        return "";
     }
 
     /**
-     * The default value may need to be escaped to be safe for json
+     * Gets the value with the key in a safe way, eg returning an empty string if there was no value for the key.
      */
-    private static String safeDefaultValue(String value) {
-        if ("\"".equals(value)) {
-            return "\\\"";
-        } else if ("\\".equals(value)) {
-            return "\\\\";
-        } else {
+    public static String getSafeValue(String key, Map<String, String> rows) {
+        String value = rows.get(key);
+        if (value != null) {
             return value;
         }
+        return "";
+    }
+
+    public static String getPropertyDefaultValue(List<Map<String, String>> rows, String name) {
+        for (Map<String, String> row : rows) {
+            String defaultValue = null;
+            boolean found = false;
+            if (row.containsKey("name")) {
+                found = name.equals(row.get("name"));
+            }
+            if (row.containsKey("defaultValue")) {
+                defaultValue = row.get("defaultValue");
+            }
+            if (found) {
+                return defaultValue;
+            }
+        }
+        return null;
+    }
+
+    public static String getPropertyDescriptionValue(List<Map<String, String>> rows, String name) {
+        for (Map<String, String> row : rows) {
+            String description = null;
+            boolean found = false;
+            if (row.containsKey("name")) {
+                found = name.equals(row.get("name"));
+            }
+            if (row.containsKey("description")) {
+                description = row.get("description");
+            }
+            if (found) {
+                return description;
+            }
+        }
+        return null;
+    }
+
+    public static String getPropertyJavaType(List<Map<String, String>> rows, String name) {
+        for (Map<String, String> row : rows) {
+            String javaType = null;
+            boolean found = false;
+            if (row.containsKey("name")) {
+                found = name.equals(row.get("name"));
+            }
+            if (row.containsKey("javaType")) {
+                javaType = row.get("javaType");
+            }
+            if (found) {
+                return javaType;
+            }
+        }
+        return null;
+    }
+
+    public static String getPropertyType(List<Map<String, String>> rows, String name) {
+        for (Map<String, String> row : rows) {
+            String type = null;
+            boolean found = false;
+            if (row.containsKey("name")) {
+                found = name.equals(row.get("name"));
+            }
+            if (row.containsKey("type")) {
+                type = row.get("type");
+            }
+            if (found) {
+                return type;
+            }
+        }
+        return null;
     }
 
 }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/PackageHelper.java
similarity index 69%
rename from tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java
rename to tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/PackageHelper.java
index 61bde68..9136f2b 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java
+++ b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/PackageHelper.java
@@ -14,51 +14,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.maven.packaging;
+package org.apache.camel.tooling.util;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileFilter;
-import java.io.FileOutputStream;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.LineNumberReader;
+import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 
-import org.apache.maven.model.Resource;
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.project.MavenProject;
-import org.sonatype.plexus.build.incremental.BuildContext;
-
+/**
+ * Utility class to find, read json files.
+ */
 public final class PackageHelper {
 
+    public static final String JSON_SUFIX = ".json";
+
     private PackageHelper() {
     }
-    
-    public static boolean haveResourcesChanged(Log log, MavenProject project, BuildContext buildContext, String suffix) {
-        String baseDir = project.getBasedir().getAbsolutePath();
-        for (Resource r : project.getBuild().getResources()) {
-            File file = new File(r.getDirectory());
-            if (file.isAbsolute()) {
-                file = new File(r.getDirectory().substring(baseDir.length() + 1));
-            }
-            String path = file.getPath() + "/" + suffix;
-            if (log.isDebugEnabled()) {
-                log.debug("Checking  if " + path + " (" + r.getDirectory() + "/" + suffix + ") has changed.");
-            }
-            if (buildContext.hasDelta(path)) {
-                log.debug("Indeed " + suffix + " has changed.");
-                return true;
-            }
-        }
-        return false;
-    }
 
     /**
      * Loads the entire stream into memory as a String and returns it.
@@ -89,13 +72,12 @@ public final class PackageHelper {
         }
     }
 
+    public static String loadText(File file) throws IOException {
+        return loadText(new FileInputStream(file));
+    }
+
     public static void writeText(File file, String text) throws IOException {
-        FileOutputStream fos = new FileOutputStream(file, false);
-        try {
-            fos.write(text.getBytes());
-        } finally {
-            fos.close();
-        }
+        FileUtil.updateFile(file.toPath(), text);
     }
 
     public static String after(String text, String after) {
@@ -128,33 +110,48 @@ public final class PackageHelper {
         return answer;
     }
 
-    public static Set<File> findJsonFiles(File dir, FileFilter filter) {
-        Set<File> files = new TreeSet<>();
-        findJsonFiles(dir, files, filter);
+    public static String fileToString(File file) throws IOException {
+        byte[] encoded = Files.readAllBytes(Paths.get(file.toURI()));
+        return new String(encoded, Charset.defaultCharset());
+    }
 
-        return files;
+    public static Map<String, File> findJsonFiles(File rootDir) {
+        Map<String, File> results = new HashMap<>();
+        findJsonFiles0(rootDir, results, new CamelComponentsModelFilter());
+        return results;
     }
 
-    public static void findJsonFiles(File dir, Set<File> found, FileFilter filter) {
+    public static void findJsonFiles(File rootDir, Set<File> files, FileFilter filter) {
+        Map<String, File> results = new HashMap<>();
+        findJsonFiles0(rootDir, results, new CamelComponentsModelFilter());
+        files.addAll(results.values());
+    }
+
+    public static Map<String, File> findJsonFiles(File rootDir, FileFilter filter) {
+        Map<String, File> results = new HashMap<>();
+        findJsonFiles0(rootDir, results, filter);
+        return results;
+    }
+
+    private static void findJsonFiles0(File dir, Map<String, File> result, FileFilter filter) {
         File[] files = dir.listFiles(filter);
         if (files != null) {
             for (File file : files) {
                 // skip files in root dirs as Camel does not store information there but others may do
-                boolean jsonFile = file.isFile() && file.getName().endsWith(".json");
+                boolean jsonFile = file.isFile() && file.getName().endsWith(JSON_SUFIX);
                 if (jsonFile) {
-                    found.add(file);
+                    result.put(file.getName().replaceAll("\\" + JSON_SUFIX, ""), file);
                 } else if (file.isDirectory()) {
-                    findJsonFiles(file, found, filter);
+                    findJsonFiles0(file, result, filter);
                 }
             }
         }
     }
 
     public static class CamelComponentsModelFilter implements FileFilter {
-
         @Override
         public boolean accept(File pathname) {
-            return pathname.isDirectory() || pathname.getName().endsWith(".json");
+            return pathname.isDirectory() || pathname.getName().endsWith(JSON_SUFIX);
         }
     }
 
@@ -164,16 +161,16 @@ public final class PackageHelper {
         public boolean accept(File pathname) {
             String name = pathname.getName();
             boolean special = "camel-core-osgi".equals(name)
-                || "camel-core-xml".equals(name)
-                || "camel-http-base".equals(name)
-                || "camel-http-common".equals(name)
-                || "camel-jetty-common".equals(name);
+                    || "camel-core-xml".equals(name)
+                    || "camel-http-base".equals(name)
+                    || "camel-http-common".equals(name)
+                    || "camel-jetty-common".equals(name);
             boolean special2 = "camel-as2".equals(name)
-                || "camel-box".equals(name)
-                || "camel-olingo2".equals(name)
-                || "camel-olingo4".equals(name)
-                || "camel-salesforce".equals(name)
-                || "camel-debezium-common".equals(name);
+                    || "camel-box".equals(name)
+                    || "camel-olingo2".equals(name)
+                    || "camel-olingo4".equals(name)
+                    || "camel-salesforce".equals(name)
+                    || "camel-debezium-common".equals(name);
             if (special || special2) {
                 return false;
             }
diff --git a/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
new file mode 100644
index 0000000..949df76
--- /dev/null
+++ b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
@@ -0,0 +1,328 @@
+/*
+ * 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.tooling.util;
+
+import java.util.Collection;
+
+/**
+ * Some String helper methods
+ */
+public final class Strings {
+
+    private Strings() {
+        //Helper class
+    }
+
+    public static boolean isEmpty(String s) {
+        return s == null || s.trim().isEmpty();
+    }
+
+    /**
+     * Returns true if the given text is null or empty string or has <tt>null</tt> as the value
+     */
+    public static boolean isNullOrEmpty(String text) {
+        return text == null || text.length() == 0 || "null".equals(text);
+    }
+
+    public static String safeNull(String text) {
+        if (isNullOrEmpty(text)) {
+            return "";
+        } else {
+            return text;
+        }
+    }
+
+    /**
+     * Returns the value or the defaultValue if it is null
+     */
+    public static String getOrElse(String text, String defaultValue) {
+        return (text != null) ? text : defaultValue;
+    }
+
+    /**
+     * Returns the string after the given token
+     *
+     * @param text  the text
+     * @param after the token
+     * @return the text after the token, or <tt>null</tt> if text does not contain the token
+     */
+    public static String after(String text, String after) {
+        int index = text.indexOf(after);
+        if (index < 0) {
+            return null;
+        }
+        return text.substring(index + after.length());
+    }
+
+    /**
+     * Returns the canonical class name by removing any generic type information.
+     */
+    public static String canonicalClassName(String className) {
+        // remove generics
+        int pos = className.indexOf('<');
+        if (pos != -1) {
+            return className.substring(0, pos);
+        } else {
+            return className;
+        }
+    }
+
+    /**
+     * Returns the text wrapped double quotes
+     */
+    public static String doubleQuote(String text) {
+        return quote(text, "\"");
+    }
+
+    /**
+     * Returns the text wrapped single quotes
+     */
+    public static String singleQuote(String text) {
+        return quote(text, "'");
+    }
+
+    /**
+     * Wraps the text in the given quote text
+     *
+     * @param text the text to wrap in quotes
+     * @param quote the quote text added to the prefix and postfix of the text
+     *
+     * @return the text wrapped in the given quotes
+     */
+    public static String quote(String text, String quote) {
+        return quote + text + quote;
+    }
+
+    /**
+     * Clips the text between the start and end markers
+     */
+    public static String between(String text, String after, String before) {
+        text = after(text, after);
+        if (text == null) {
+            return null;
+        }
+        return before(text, before);
+    }
+
+    /**
+     * Capitalizes the name as a title
+     *
+     * @param name  the name
+     * @return as a title
+     */
+    public static String asTitle(String name) {
+        StringBuilder sb = new StringBuilder();
+        for (char c : name.toCharArray()) {
+            boolean upper = Character.isUpperCase(c);
+            boolean first = sb.length() == 0;
+            if (first) {
+                sb.append(Character.toUpperCase(c));
+            } else if (upper) {
+                char prev = sb.charAt(sb.length() - 1);
+                if (!Character.isUpperCase(prev)) {
+                    // append space if previous is not upper
+                    sb.append(' ');
+                }
+                sb.append(c);
+            } else {
+                sb.append(Character.toLowerCase(c));
+            }
+        }
+        return sb.toString().trim();
+    }
+
+    public static String before(String text, String before) {
+        int index = text.indexOf(before);
+        if (index < 0) {
+            return null;
+        }
+        return text.substring(0, index);
+    }
+
+    public static String indentCollection(String indent, Collection<String> list) {
+        StringBuilder sb = new StringBuilder();
+        for (String text : list) {
+            sb.append(indent).append(text);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Converts the value to use title style instead of dash cased
+     */
+    public static String camelDashToTitle(String value) {
+        StringBuilder sb = new StringBuilder(value.length());
+        boolean dash = false;
+
+        for (char c : value.toCharArray()) {
+            if ('-' == c) {
+                dash = true;
+                continue;
+            }
+
+            if (dash) {
+                sb.append(' ');
+                sb.append(Character.toUpperCase(c));
+            } else {
+                // upper case first
+                if (sb.length() == 0) {
+                    sb.append(Character.toUpperCase(c));
+                } else {
+                    sb.append(c);
+                }
+            }
+            dash = false;
+        }
+        return sb.toString();
+    }
+
+    public static String cutLastZeroDigit(String version) {
+        String answer = version;
+        // cut last digit so its not 2.18.0 but 2.18
+        String[] parts = version.split("\\.");
+        if (parts.length == 3 && parts[2].equals("0")) {
+            answer = parts[0] + "." + parts[1];
+        }
+        return answer;
+    }
+
+    /**
+     * To wrap long camel cased texts by words.
+     *
+     * @param option  the option which is camel cased.
+     * @param watermark a watermark to denote the size to cut after
+     * @param lineSep the new line to use when breaking into a new line
+     */
+    public static String wrapCamelCaseWords(String option, int watermark, String lineSep) {
+        String text = option.replaceAll("(?=[A-Z][a-z])", " ");
+        text = wrapWords(text, "", lineSep, watermark, false);
+        return Character.toUpperCase(text.charAt(0)) + text.substring(1);
+    }
+
+    /**
+     * To wrap a big line by words.
+     * @param line the big line
+     * @param wordSep the word separator
+     * @param lineSep the new line to use when breaking into a new line
+     * @param watermark a watermark to denote the size to cut after
+     * @param wrapLongWords whether to wrap long words
+     */
+    public static String wrapWords(String line, String wordSep, String lineSep, int watermark, boolean wrapLongWords) {
+        if (line == null) {
+            return null;
+        } else {
+            if (lineSep == null) {
+                lineSep = System.lineSeparator();
+            }
+            if (wordSep == null) {
+                wordSep = "";
+            }
+
+            if (watermark < 1) {
+                watermark = 1;
+            }
+
+            int inputLineLength = line.length();
+            int offset = 0;
+            StringBuilder sb = new StringBuilder(inputLineLength + 32);
+            int currentLength = 0;
+            while (offset < inputLineLength) {
+                if (line.charAt(offset) == ' ') {
+                    offset++;
+                    continue;
+                }
+                int next = line.indexOf(' ', offset);
+                if (next < 0) {
+                    next = inputLineLength;
+                    if (wrapLongWords && inputLineLength - offset > watermark) {
+                        if (currentLength > 0) {
+                            sb.append(wordSep);
+                            currentLength += wordSep.length();
+                        }
+                        sb.append(line, offset, watermark - currentLength);
+                        sb.append(lineSep);
+                        offset += watermark - currentLength;
+                    }
+                }
+                if (currentLength + (currentLength > 0 ? wordSep.length() : 0) + next - offset <= watermark) {
+                    if (currentLength > 0) {
+                        sb.append(wordSep);
+                        currentLength += wordSep.length();
+                    }
+                    sb.append(line, offset, next);
+                    currentLength += next - offset;
+                    offset = next + 1;
+                } else {
+                    sb.append(lineSep);
+                    sb.append(line, offset, next);
+                    currentLength = next - offset;
+                    offset = next + 1;
+                }
+            }
+            /*
+            while (inputLineLength - offset > watermark) {
+                if (line.charAt(offset) == ' ') {
+                    ++offset;
+                } else {
+                    int spaceToWrapAt = line.lastIndexOf(' ', watermark + offset);
+                    int spaces = 0;
+                    for (int i = offset; i < spaceToWrapAt; i++) {
+                        spaces += line.charAt(i) == ' ' ? 1 : 0;
+                    }
+                    if (spaceToWrapAt >= offset) {
+                        sb.append(line, offset, spaceToWrapAt);
+                        sb.append(newLine);
+                        offset = spaceToWrapAt + 1;
+                    } else if (wrapLongWords) {
+                        sb.append(line, offset, watermark + offset);
+                        sb.append(newLine);
+                        offset += watermark;
+                    } else {
+                        spaceToWrapAt = line.indexOf(' ', watermark + offset);
+                        if (spaceToWrapAt >= 0) {
+                            sb.append(line, offset, spaceToWrapAt);
+                            sb.append(newLine);
+                            offset = spaceToWrapAt + 1;
+                        } else {
+                            sb.append(line, offset, line.length());
+                            offset = inputLineLength;
+                        }
+                    }
+                }
+            }
+
+            sb.append(line, offset, line.length());
+            */
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Returns the base class name, i.e. without package and generic related
+     * information.
+     *
+     * @param className The class name which base class is to be computed.
+     * @return the base class name, i.e. without package and generic related
+     *         information.
+     */
+    public static String getClassShortName(String className) {
+        if (className != null) {
+            return className.replaceAll("<.*>", "").replaceAll(".*[.]([^.]+)", "$1");
+        }
+        return className;
+    }
+}
diff --git a/tooling/camel-tooling-util/src/main/resources/META-INF/LICENSE.txt b/tooling/camel-tooling-util/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/tooling/camel-tooling-util/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/tooling/camel-tooling-util/src/main/resources/META-INF/NOTICE.txt b/tooling/camel-tooling-util/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..0291ff5
--- /dev/null
+++ b/tooling/camel-tooling-util/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,14 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   This product includes software developed by
+   Clifton Labs (https://github.com/cliftonlabs/json-simple).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/tooling/apt/src/test/java/org/apache/camel/tools/apt/JsonSchemaHelperTest.java b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/JSonSchemaHelperTest.java
similarity index 94%
rename from tooling/apt/src/test/java/org/apache/camel/tools/apt/JsonSchemaHelperTest.java
rename to tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/JSonSchemaHelperTest.java
index 1c267c4..9839431 100644
--- a/tooling/apt/src/test/java/org/apache/camel/tools/apt/JsonSchemaHelperTest.java
+++ b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/JSonSchemaHelperTest.java
@@ -14,13 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.tools.apt;
+package org.apache.camel.tooling.util;
 
-import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
 import org.junit.Assert;
 import org.junit.Test;
 
-public class JsonSchemaHelperTest {
+public class JSonSchemaHelperTest {
 
     private static final String JAVADOC = ""
         + "     * When in streaming mode, then the splitter splits the original message on-demand, and each splitted\n"
@@ -72,13 +72,13 @@ public class JsonSchemaHelperTest {
     @Test
     public void testSanitizeJavaDoc() throws Exception {
         String s = "* more memory. The total size is provided in the {@link org.apache.camel.Exchange#SPLIT_SIZE} header.";
-        String s2 = JsonSchemaHelper.sanitizeDescription(s, false);
+        String s2 = JSonSchemaHelper.sanitizeDescription(s, false);
         Assert.assertEquals("more memory. The total size is provided in the org.apache.camel.Exchange#SPLIT_SIZE header.", s2);
 
-        String out = JsonSchemaHelper.sanitizeDescription(JAVADOC, false);
+        String out = JSonSchemaHelper.sanitizeDescription(JAVADOC, false);
         Assert.assertEquals(EXPECTED_OUT, out);
 
-        String out2 = JsonSchemaHelper.sanitizeDescription(JAVADOC2, false);
+        String out2 = JSonSchemaHelper.sanitizeDescription(JAVADOC2, false);
         Assert.assertEquals(EXPECTED_OUT2, out2);
     }
 }
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/java/org/apache/camel/maven/PackageHelperTest.java b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/PackageHelperTest.java
similarity index 94%
rename from tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/java/org/apache/camel/maven/PackageHelperTest.java
rename to tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/PackageHelperTest.java
index 4ff82c0..5342097 100644
--- a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/java/org/apache/camel/maven/PackageHelperTest.java
+++ b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/PackageHelperTest.java
@@ -14,11 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.maven;
+package org.apache.camel.tooling.util;
 
 import java.io.File;
 import java.util.Map;
 
+import org.apache.camel.tooling.util.PackageHelper;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
diff --git a/tooling/apt/src/test/java/org/apache/camel/tools/apt/StringsTest.java b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/ResourceUtils.java
similarity index 53%
rename from tooling/apt/src/test/java/org/apache/camel/tools/apt/StringsTest.java
rename to tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/ResourceUtils.java
index 0012ff5..152d3ca 100644
--- a/tooling/apt/src/test/java/org/apache/camel/tools/apt/StringsTest.java
+++ b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/ResourceUtils.java
@@ -14,25 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.tools.apt;
+package org.apache.camel.tooling.util;
 
-import org.junit.Test;
+import java.io.File;
 
-import static org.apache.camel.tools.apt.helper.Strings.asTitle;
-import static org.apache.camel.tools.apt.helper.Strings.between;
-import static org.junit.Assert.assertEquals;
+public final class ResourceUtils {
 
-public class StringsTest {
-
-    @Test
-    public void testBetween() {
-        assertEquals("org.apache.camel.model.OnCompletionDefinition", between("java.util.List<org.apache.camel.model.OnCompletionDefinition>", "<", ">"));
+    private ResourceUtils() {
+        // noop
     }
 
-    @Test
-    public void testAsTitle() {
-        assertEquals("Broker URL", asTitle("brokerURL"));
-        assertEquals("Expose All Queues", asTitle("exposeAllQueues"));
-        assertEquals("Reply To Concurrent Consumers", asTitle("replyToConcurrentConsumers"));
+    public static File getResourceAsFile(String pathToFile) throws Exception {
+        return new File(ResourceUtils.class.getClassLoader().getResource(pathToFile).getFile());
     }
+
 }
diff --git a/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/StringsTest.java b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/StringsTest.java
new file mode 100644
index 0000000..14f8e9f
--- /dev/null
+++ b/tooling/camel-tooling-util/src/test/java/org/apache/camel/tooling/util/StringsTest.java
@@ -0,0 +1,40 @@
+package org.apache.camel.tooling.util;
+
+import org.junit.Test;
+
+import static org.apache.camel.tooling.util.Strings.asTitle;
+import static org.apache.camel.tooling.util.Strings.between;
+import static org.junit.Assert.assertEquals;
+
+public class StringsTest {
+
+    @Test
+    public void testBetween() {
+        assertEquals("org.apache.camel.model.OnCompletionDefinition", between("java.util.List<org.apache.camel.model.OnCompletionDefinition>", "<", ">"));
+    }
+
+    @Test
+    public void testAsTitle() {
+        assertEquals("Broker URL", asTitle("brokerURL"));
+        assertEquals("Expose All Queues", asTitle("exposeAllQueues"));
+        assertEquals("Reply To Concurrent Consumers", asTitle("replyToConcurrentConsumers"));
+    }
+
+    @Test
+    public void testWrap() {
+        assertEquals("Hello WorldFoo Nar", wrap("HelloWorldFooNar", 8));
+        assertEquals("UseMessageIDAs CorrelationID", wrap("useMessageIDAsCorrelationID", 25));
+        assertEquals("ReplyToCacheLevelName", wrap("replyToCacheLevelName", 25));
+        assertEquals("AllowReplyManagerQuick Stop", wrap("allowReplyManagerQuickStop", 25));
+        assertEquals("AcknowledgementModeName", wrap("acknowledgementModeName", 25));
+        assertEquals("ReplyToCacheLevelName", wrap("replyToCacheLevelName", 25));
+        assertEquals("ReplyToOnTimeoutMax ConcurrentConsumers", wrap("replyToOnTimeoutMaxConcurrentConsumers", 25));
+        assertEquals("ReplyToOnTimeoutMax ConcurrentConsumers", wrap("replyToOnTimeoutMaxConcurrentConsumers", 23));
+        assertEquals("ReplyToMaxConcurrent Consumers", wrap("replyToMaxConcurrentConsumers", 23));
+
+    }
+
+    private String wrap(String str, int watermark) {
+        return Strings.wrapCamelCaseWords(str, watermark, " ");
+    }
+}
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/filecontent/a.txt b/tooling/camel-tooling-util/src/test/resources/filecontent/a.txt
similarity index 100%
rename from tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/filecontent/a.txt
rename to tooling/camel-tooling-util/src/test/resources/filecontent/a.txt
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/a.json b/tooling/camel-tooling-util/src/test/resources/json/a.json
similarity index 100%
rename from tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/a.json
rename to tooling/camel-tooling-util/src/test/resources/json/a.json
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/aop.json b/tooling/camel-tooling-util/src/test/resources/json/aop.json
similarity index 100%
rename from tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/aop.json
rename to tooling/camel-tooling-util/src/test/resources/json/aop.json
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/b.json b/tooling/camel-tooling-util/src/test/resources/json/b.json
similarity index 100%
rename from tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/b.json
rename to tooling/camel-tooling-util/src/test/resources/json/b.json
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/c.txt b/tooling/camel-tooling-util/src/test/resources/json/c.txt
similarity index 100%
rename from tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/test/resources/json/c.txt
rename to tooling/camel-tooling-util/src/test/resources/json/c.txt
diff --git a/tooling/maven/bom-generator-maven-plugin/pom.xml b/tooling/maven/bom-generator-maven-plugin/pom.xml
index e7e0965..7a8e30e 100644
--- a/tooling/maven/bom-generator-maven-plugin/pom.xml
+++ b/tooling/maven/bom-generator-maven-plugin/pom.xml
@@ -107,6 +107,10 @@
             <artifactId>log4j-slf4j-impl</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-util</artifactId>
+        </dependency>
 
     </dependencies>
 
diff --git a/tooling/maven/bom-generator-maven-plugin/src/main/java/org/apache/camel/maven/bom/generator/BomGeneratorMojo.java b/tooling/maven/bom-generator-maven-plugin/src/main/java/org/apache/camel/maven/bom/generator/BomGeneratorMojo.java
index d1735f4..bc1d346 100644
--- a/tooling/maven/bom-generator-maven-plugin/src/main/java/org/apache/camel/maven/bom/generator/BomGeneratorMojo.java
+++ b/tooling/maven/bom-generator-maven-plugin/src/main/java/org/apache/camel/maven/bom/generator/BomGeneratorMojo.java
@@ -18,12 +18,10 @@ package org.apache.camel.maven.bom.generator;
 
 import java.io.File;
 import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -48,7 +46,7 @@ import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import org.apache.commons.io.IOUtils;
+import org.apache.camel.tooling.util.FileUtil;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -120,7 +118,7 @@ public class BomGeneratorMojo extends AbstractMojo {
      * List of Remote Repositories used by the resolver
      */
     @Parameter(property = "project.remoteArtifactRepositories", readonly = true, required = true)
-    protected List remoteRepositories;
+    protected List<ArtifactRepository> remoteRepositories;
 
     /**
      * Location of the local repository.
@@ -185,7 +183,7 @@ public class BomGeneratorMojo extends AbstractMojo {
             }
         }
 
-        Collections.sort(outDependencies, (d1, d2) -> (d1.getGroupId() + ":" + d1.getArtifactId()).compareTo(d2.getGroupId() + ":" + d2.getArtifactId()));
+        outDependencies.sort(Comparator.comparing(d -> d.getGroupId() + ":" + d.getArtifactId()));
 
         return outDependencies;
     }
@@ -234,8 +232,6 @@ public class BomGeneratorMojo extends AbstractMojo {
 
         DOMSource source = new DOMSource(pom);
 
-        targetPom.getParentFile().mkdirs();
-
         String content;
         try (StringWriter out = new StringWriter()) {
             StreamResult result = new StreamResult(out);
@@ -245,36 +241,9 @@ public class BomGeneratorMojo extends AbstractMojo {
 
         // Fix header formatting problem
         content = content.replaceFirst("-->", "-->\n");
-        writeFileIfChanged(content, targetPom);
-    }
-
-    private void writeFileIfChanged(String content, File file) throws IOException {
-        boolean write = true;
-
-        if (file.exists()) {
-            try (FileReader fr = new FileReader(file)) {
-                String oldContent = IOUtils.toString(fr);
-                if (!content.equals(oldContent)) {
-                    getLog().info("File: " + file.getAbsolutePath() + " is updated");
-                    fr.close();
-                } else {
-                    getLog().info("File " + file.getAbsolutePath() + " is not changed");
-                    write = false;
-                }
-            }
-        } else {
-            File parent = file.getParentFile();
-            parent.mkdirs();
-        }
-
-        if (write) {
-            try (FileWriter fw = new FileWriter(file)) {
-                IOUtils.write(content, fw);
-            }
-        }
+        FileUtil.updateFile(targetPom.toPath(), content);
     }
 
-
     private void overwriteDependencyManagement(Document pom, List<Dependency> dependencies) throws Exception {
         XPath xpath = XPathFactory.newInstance().newXPath();
         XPathExpression expr = xpath.compile("/project/dependencyManagement/dependencies");
diff --git a/tooling/maven/camel-api-component-maven-plugin/pom.xml b/tooling/maven/camel-api-component-maven-plugin/pom.xml
index 4058371..143327b 100644
--- a/tooling/maven/camel-api-component-maven-plugin/pom.xml
+++ b/tooling/maven/camel-api-component-maven-plugin/pom.xml
@@ -46,6 +46,11 @@
     <dependencies>
 
         <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-util</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-core</artifactId>
             <exclusions>
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractGeneratorMojo.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractGeneratorMojo.java
index 92cf19c..85c8aa2 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractGeneratorMojo.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractGeneratorMojo.java
@@ -20,16 +20,13 @@ import java.io.File;
 import java.io.IOError;
 import java.io.IOException;
 import java.io.StringWriter;
-import java.io.Writer;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Date;
-import java.util.Objects;
 import java.util.Properties;
 
+import org.apache.camel.tooling.util.FileUtil;
 import org.apache.camel.util.function.ThrowingHelper;
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 import org.apache.maven.plugin.AbstractMojo;
@@ -180,22 +177,7 @@ public abstract class AbstractGeneratorMojo extends AbstractMojo {
 
     public static void updateResource(BuildContext buildContext, Path out, String data) {
         try {
-            if (data == null) {
-                if (Files.isRegularFile(out)) {
-                    Files.delete(out);
-                    refresh(buildContext, out);
-                }
-            } else {
-                if (Files.isRegularFile(out) && Files.isReadable(out)) {
-                    String content = new String(Files.readAllBytes(out), StandardCharsets.UTF_8);
-                    if (Objects.equals(content, data)) {
-                        return;
-                    }
-                }
-                Files.createDirectories(out.getParent());
-                try (Writer w = Files.newBufferedWriter(out, StandardCharsets.UTF_8)) {
-                    w.append(data);
-                }
+            if (FileUtil.updateFile(out, data)) {
                 refresh(buildContext, out);
             }
         } catch (IOException e) {
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/pom.xml b/tooling/maven/camel-eip-documentation-enricher-maven-plugin/pom.xml
index d706560..6af52fc 100644
--- a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/pom.xml
+++ b/tooling/maven/camel-eip-documentation-enricher-maven-plugin/pom.xml
@@ -82,6 +82,14 @@
             <artifactId>camel-core</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-util-json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-util</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
             <version>${commons-lang3-version}</version>
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/DocumentationEnricher.java b/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/DocumentationEnricher.java
index 12d528d..e6cfd0a 100644
--- a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/DocumentationEnricher.java
+++ b/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/DocumentationEnricher.java
@@ -28,6 +28,7 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import org.apache.camel.support.JSonSchemaHelper;
+import org.apache.camel.tooling.util.PackageHelper;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.text.WordUtils;
 import org.apache.maven.plugin.logging.Log;
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/EipDocumentationEnricherMojo.java b/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/EipDocumentationEnricherMojo.java
index 11e8500..d440a20 100644
--- a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/EipDocumentationEnricherMojo.java
+++ b/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/EipDocumentationEnricherMojo.java
@@ -36,6 +36,7 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
+import org.apache.camel.tooling.util.PackageHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.maven.plugin.AbstractMojo;
diff --git a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/PackageHelper.java b/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/PackageHelper.java
deleted file mode 100644
index 76268c9..0000000
--- a/tooling/maven/camel-eip-documentation-enricher-maven-plugin/src/main/java/org/apache/camel/maven/PackageHelper.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Utility class to find, read json files.
- */
-public final class PackageHelper {
-
-    private PackageHelper() {
-    }
-
-    public static String fileToString(File file) throws IOException {
-        byte[] encoded = Files.readAllBytes(Paths.get(file.toURI()));
-        return new String(encoded, Charset.defaultCharset());
-    }
-
-    public static Map<String, File> findJsonFiles(File rootDir) {
-        Map<String, File> results = new HashMap<>();
-        findJsonFiles0(rootDir, results, new CamelComponentsModelFilter());
-        return results;
-    }
-
-    private static void findJsonFiles0(File dir, Map<String, File> result, FileFilter filter) {
-        File[] files = dir.listFiles(filter);
-        if (files != null) {
-            for (File file : files) {
-                // skip files in root dirs as Camel does not store information there but others may do
-                boolean jsonFile = file.isFile() && file.getName().endsWith(Constants.JSON_SUFIX);
-                if (jsonFile) {
-                    result.put(file.getName().replaceAll("\\" + Constants.JSON_SUFIX, ""), file);
-                } else if (file.isDirectory()) {
-                    findJsonFiles0(file, result, filter);
-                }
-            }
-        }
-    }
-
-    private static class CamelComponentsModelFilter implements FileFilter {
-        @Override
-        public boolean accept(File pathname) {
-            return pathname.isDirectory() || pathname.getName().endsWith(Constants.JSON_SUFIX);
-        }
-    }
-}
diff --git a/tooling/maven/camel-main-package-maven-plugin/pom.xml b/tooling/maven/camel-main-package-maven-plugin/pom.xml
index ba676ad..690ba37 100644
--- a/tooling/maven/camel-main-package-maven-plugin/pom.xml
+++ b/tooling/maven/camel-main-package-maven-plugin/pom.xml
@@ -88,6 +88,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-util</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
             <artifactId>camel-util-json</artifactId>
         </dependency>
 
diff --git a/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java b/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java
index 3b04d36..819d513 100644
--- a/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java
+++ b/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java
@@ -17,7 +17,6 @@
 package org.apache.camel.maven;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -26,7 +25,7 @@ import java.util.Map;
 
 import org.apache.camel.main.parser.ConfigurationModel;
 import org.apache.camel.main.parser.MainConfigurationParser;
-import org.apache.camel.util.StringHelper;
+import org.apache.camel.tooling.util.FileUtil;
 import org.apache.camel.util.json.Jsoner;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -83,7 +82,7 @@ public class PrepareCamelMainMojo extends AbstractMojo {
                     prefix = "camel.main.";
                 }
                 final String namePrefix = prefix;
-                model.stream().forEach(m -> m.setName(namePrefix + m.getName()));
+                model.forEach(m -> m.setName(namePrefix + m.getName()));
                 data.addAll(model);
             } catch (Exception e) {
                 throw new MojoFailureException("Error parsing file " + file + " due " + e.getMessage(), e);
@@ -94,7 +93,7 @@ public class PrepareCamelMainMojo extends AbstractMojo {
         File restConfig = new File(buildDir, "../../camel-api/src/main/java/org/apache/camel/spi/RestConfiguration.java");
         try {
             List<ConfigurationModel> model = parser.parseConfigurationSource(restConfig);
-            model.stream().forEach(m -> m.setName("camel.rest." + m.getName()));
+            model.forEach(m -> m.setName("camel.rest." + m.getName()));
             data.addAll(model);
         } catch (Exception e) {
             throw new MojoFailureException("Error parsing file " + restConfig + " due " + e.getMessage(), e);
@@ -112,16 +111,15 @@ public class PrepareCamelMainMojo extends AbstractMojo {
         });
 
         if (!data.isEmpty()) {
-            List list = new ArrayList();
-            for (int i = 0; i < data.size(); i++) {
-                ConfigurationModel row = data.get(i);
+            List<Object> list = new ArrayList<>();
+            for (ConfigurationModel row : data) {
                 String name = camelCaseToDash(row.getName());
                 String javaType = row.getJavaType();
                 String desc = sanitizeDescription(row.getDescription(), false);
                 String sourceType = row.getSourceType();
                 String defaultValue = row.getDefaultValue();
 
-                Map p = new LinkedHashMap();
+                Map<String, Object> p = new LinkedHashMap<>();
                 p.put("name", name);
                 p.put("type", javaType);
                 p.put("sourceType", sourceType);
@@ -136,20 +134,20 @@ public class PrepareCamelMainMojo extends AbstractMojo {
                 list.add(p);
             }
 
-            List groups = new ArrayList();
-            Map group1 = new LinkedHashMap();
+            List<Object> groups = new ArrayList<>();
+            Map<String, Object> group1 = new LinkedHashMap<>();
             group1.put("name", "camel.main");
             group1.put("description", "camel-main configurations.");
             group1.put("sourceType", "org.apache.camel.main.DefaultConfigurationProperties");
-            Map group2 = new LinkedHashMap();
+            Map<String, Object> group2 = new LinkedHashMap<>();
             group2.put("name", "camel.hystrix");
             group2.put("description", "camel-hystrix configurations.");
             group2.put("sourceType", "org.apache.camel.main.HystrixConfigurationProperties");
-            Map group3 = new LinkedHashMap();
+            Map<String, Object> group3 = new LinkedHashMap<>();
             group3.put("name", "camel.resilience4j");
             group3.put("description", "camel-resilience4j configurations.");
             group3.put("sourceType", "org.apache.camel.main.Resilience4jConfigurationProperties");
-            Map group4 = new LinkedHashMap();
+            Map<String, Object> group4 = new LinkedHashMap<>();
             group4.put("name", "camel.rest");
             group4.put("description", "camel-rest configurations.");
             group4.put("sourceType", "org.apache.camel.spi.RestConfiguration");
@@ -158,20 +156,16 @@ public class PrepareCamelMainMojo extends AbstractMojo {
             groups.add(group3);
             groups.add(group4);
 
-            Map map = new LinkedHashMap();
+            Map<String, Object> map = new LinkedHashMap<>();
             map.put("groups", groups);
             map.put("properties", list);
 
             String json = Jsoner.serialize(map);
             json = Jsoner.prettyPrint(json);
 
-            outFolder.mkdirs();
             File file = new File(outFolder, "camel-main-configuration-metadata.json");
             try {
-                FileOutputStream fos = new FileOutputStream(file, false);
-                fos.write(json.getBytes());
-                fos.close();
-                getLog().info("Created file: " + file);
+                FileUtil.updateFile(file.toPath(), json);
             } catch (Throwable e) {
                 throw new MojoFailureException("Cannot write to file " + file + " due " + e.getMessage(), e);
             }
diff --git a/tooling/maven/camel-package-maven-plugin/pom.xml b/tooling/maven/camel-package-maven-plugin/pom.xml
index 4b4cf6f..088a435 100644
--- a/tooling/maven/camel-package-maven-plugin/pom.xml
+++ b/tooling/maven/camel-package-maven-plugin/pom.xml
@@ -49,7 +49,10 @@
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-util-json</artifactId>
-            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-util</artifactId>
         </dependency>
 
         <dependency>
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGeneratorMojo.java
index 82c00e3..ab4a90f 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGeneratorMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGeneratorMojo.java
@@ -16,16 +16,16 @@
  */
 package org.apache.camel.maven.packaging;
 
+import java.io.File;
 import java.io.IOError;
 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.util.Collections;
-import java.util.Objects;
 
+import org.apache.camel.tooling.util.FileUtil;
+import org.apache.maven.model.Resource;
 import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
@@ -96,22 +96,7 @@ public abstract class AbstractGeneratorMojo extends AbstractMojo {
 
     public static void updateResource(BuildContext buildContext, Path out, String data) {
         try {
-            if (data == null) {
-                if (Files.isRegularFile(out)) {
-                    Files.delete(out);
-                    refresh(buildContext, out);
-                }
-            } else {
-                if (Files.isRegularFile(out) && Files.isReadable(out)) {
-                    String content = new String(Files.readAllBytes(out), StandardCharsets.UTF_8);
-                    if (Objects.equals(content, data)) {
-                        return;
-                    }
-                }
-                Files.createDirectories(out.getParent());
-                try (Writer w = Files.newBufferedWriter(out, StandardCharsets.UTF_8)) {
-                    w.append(data);
-                }
+            if (FileUtil.updateFile(out, data)) {
                 refresh(buildContext, out);
             }
         } catch (IOException e) {
@@ -119,4 +104,23 @@ public abstract class AbstractGeneratorMojo extends AbstractMojo {
         }
     }
 
+    public static boolean haveResourcesChanged(Log log, MavenProject project, BuildContext buildContext, String suffix) {
+        String baseDir = project.getBasedir().getAbsolutePath();
+        for (Resource r : project.getBuild().getResources()) {
+            File file = new File(r.getDirectory());
+            if (file.isAbsolute()) {
+                file = new File(r.getDirectory().substring(baseDir.length() + 1));
+            }
+            String path = file.getPath() + "/" + suffix;
+            if (log.isDebugEnabled()) {
+                log.debug("Checking  if " + path + " (" + r.getDirectory() + "/" + suffix + ") has changed.");
+            }
+            if (buildContext.hasDelta(path)) {
+                log.debug("Indeed " + suffix + " has changed.");
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointDslMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointDslMojo.java
index 3cec9ca..aa7ea71 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointDslMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointDslMojo.java
@@ -17,7 +17,6 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOError;
 import java.io.IOException;
@@ -56,10 +55,14 @@ import org.apache.camel.maven.packaging.srcgen.GenericType;
 import org.apache.camel.maven.packaging.srcgen.GenericType.BoundType;
 import org.apache.camel.maven.packaging.srcgen.JavaClass;
 import org.apache.camel.maven.packaging.srcgen.Method;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
 import org.apache.camel.spi.UriPath;
+import org.apache.camel.tooling.util.PackageHelper;
+
+import org.apache.camel.tooling.util.Strings;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -68,12 +71,11 @@ 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;
-import org.jboss.forge.roaster.model.util.Strings;
 
 import static org.apache.camel.maven.packaging.AbstractGeneratorMojo.updateResource;
-import static org.apache.camel.maven.packaging.JSonSchemaHelper.getSafeValue;
-import static org.apache.camel.maven.packaging.PackageHelper.findCamelDirectory;
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.getSafeValue;
+import static org.apache.camel.tooling.util.PackageHelper.findCamelDirectory;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
 
 /**
  * Generate Endpoint DSL source files for Components.
@@ -140,7 +142,7 @@ public class EndpointDslMojo extends AbstractMojo {
             outputDir = findCamelDirectory(baseDir, "core/camel-endpointdsl/src/main/java");
         }
 
-        Map<File, Supplier<String>> files = PackageHelper.findJsonFiles(buildDir, p -> p.isDirectory() || p.getName().endsWith(".json")).stream()
+        Map<File, Supplier<String>> files = PackageHelper.findJsonFiles(buildDir, p -> p.isDirectory() || p.getName().endsWith(".json")).values().stream()
             .collect(Collectors.toMap(Function.identity(), s -> cache(() -> loadJson(s))));
 
         // generate component endpoint DSL files and write them
@@ -154,8 +156,8 @@ public class EndpointDslMojo extends AbstractMojo {
     }
 
     private static String loadJson(File file) {
-        try (InputStream is = new FileInputStream(file)) {
-            return loadText(is);
+        try {
+            return loadText(file);
         } catch (IOException e) {
             throw new IOError(e);
         }
@@ -319,7 +321,7 @@ public class EndpointDslMojo extends AbstractMojo {
         generateDummyClass(packageName + ".T");
 
         String doc = "Generated by camel-package-maven-plugin - do not edit this file!";
-        if (!Strings.isBlank(model.getDescription())) {
+        if (!Strings.isEmpty(model.getDescription())) {
             doc = model.getDescription() + "\n\n" + doc;
         }
         javaClass.getJavaDoc().setText(doc);
@@ -380,7 +382,7 @@ public class EndpointDslMojo extends AbstractMojo {
                 if ("true".equals(option.getDeprecated())) {
                     fluent.addAnnotation(Deprecated.class);
                 }
-                if (!Strings.isBlank(option.getDescription())) {
+                if (!Strings.isEmpty(option.getDescription())) {
                     String desc = option.getDescription();
                     if (!desc.endsWith(".")) {
                         desc += ".";
@@ -408,7 +410,7 @@ public class EndpointDslMojo extends AbstractMojo {
                     if ("true".equals(option.getDeprecated())) {
                         fluent.addAnnotation(Deprecated.class);
                     }
-                    if (!Strings.isBlank(option.getDescription())) {
+                    if (!Strings.isEmpty(option.getDescription())) {
                         String desc = option.getDescription();
                         if (!desc.endsWith(".")) {
                             desc += ".";
@@ -487,7 +489,7 @@ public class EndpointDslMojo extends AbstractMojo {
         final List<File> allComponentsDslEndpointFactories = loadAllComponentsDslEndpointFactoriesAsFile();
 
         CompilationUnit endpointBuilderUnit = new CompilationUnit();
-        endpointBuilderUnit.setPackageDeclaration(StringHelper.before(packageName, ".dsl"));
+        endpointBuilderUnit.setPackageDeclaration(Strings.before(packageName, ".dsl"));
         endpointBuilderUnit.addImport("java.util.List");
         endpointBuilderUnit.addImport("java.util.stream.Collectors");
         endpointBuilderUnit.addImport("java.util.stream.Stream");
@@ -579,7 +581,7 @@ public class EndpointDslMojo extends AbstractMojo {
         final List<File> allComponentsDslEndpointFactories = loadAllComponentsDslEndpointFactoriesAsFile();
 
         CompilationUnit endpointBuilderUnit = new CompilationUnit();
-        endpointBuilderUnit.setPackageDeclaration(StringHelper.before(packageName, ".dsl"));
+        endpointBuilderUnit.setPackageDeclaration(Strings.before(packageName, ".dsl"));
 
         endpointBuilderUnit.addOrphanComment(new LineComment("CHECKSTYLE:OFF"));
 
@@ -703,24 +705,20 @@ public class EndpointDslMojo extends AbstractMojo {
                     desc += " <strong>deprecated</strong>";
                 }
                 desc += "\n" + option.getDescription();
-                if (!StringHelper.isEmpty(option.getDefaultValue())) {
+                if (!Strings.isEmpty(option.getDefaultValue())) {
                     desc += "\nDefault value: " + option.getDefaultValue();
                 }
-                if (!StringHelper.isEmpty(option.getEnumValues())) {
-                    desc += "\nThe value can be one of: " + wrapEnumValues(option.getEnumValues(), 120);
+                if (!Strings.isEmpty(option.getEnumValues())) {
+                    desc += "\nThe value can be one of: " + wrapEnumValues(option.getEnumValues());
                 }
             }
         }
         return desc;
     }
 
-    private String wrapEnumValues(String enumValues, int watermark) {
+    private String wrapEnumValues(String enumValues) {
         // comma to space so we can wrap words (which uses space)
-        String text = enumValues.replace(',', ' ');
-        String wrapped = StringHelper.wrapWords(text, "\n", watermark, true);
-        // back to comma again
-        wrapped = wrapped.replaceAll("\\s", ", ");
-        return wrapped;
+        return enumValues.replaceAll(",",", ");
     }
 
     private String getEndpointName(String type) {
@@ -766,11 +764,11 @@ public class EndpointDslMojo extends AbstractMojo {
             for (Field f : cl.getDeclaredFields()) {
                 String n = f.getName();
                 UriPath path = f.getAnnotation(UriPath.class);
-                if (path != null && !Strings.isBlank(path.name())) {
+                if (path != null && !Strings.isEmpty(path.name())) {
                     n = path.name();
                 }
                 UriParam param = f.getAnnotation(UriParam.class);
-                if (param != null && !Strings.isBlank(param.name())) {
+                if (param != null && !Strings.isEmpty(param.name())) {
                     n = param.name();
                 }
                 if (n.equals(option.getName())) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java
deleted file mode 100644
index 7638755..0000000
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import org.apache.camel.util.json.JsonObject;
-import org.apache.camel.util.json.Jsoner;
-
-public final class JSonSchemaHelper {
-
-    private JSonSchemaHelper() {
-    }
-
-    /**
-     * Parses the json schema to split it into a list or rows, where each row contains key value pairs with the metadata
-     *
-     * @param group the group to parse from such as <tt>component</tt>, <tt>componentProperties</tt>, or <tt>properties</tt>.
-     * @param json the json
-     * @return a list of all the rows, where each row is a set of key value pairs with metadata
-     */
-    public static List<Map<String, String>> parseJsonSchema(String group, String json, boolean parseProperties) {
-        List<Map<String, String>> answer = new ArrayList<>();
-        if (json == null) {
-            return answer;
-        }
-
-        // convert into a List<Map<String, String>> structure which is expected as output from this parser
-        try {
-            JsonObject output = (JsonObject) Jsoner.deserialize(json);
-            for (String key : output.keySet()) {
-                Map<?, ?> row = output.getMap(key);
-                if (key.equals(group)) {
-                    if (parseProperties) {
-                        // flattern each entry in the row with name as they key, and its value as the content (its a map also)
-                        for (Object obj : row.entrySet()) {
-                            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
-                            Map<String, String> newRow = new LinkedHashMap<>();
-                            newRow.put("name", entry.getKey().toString());
-
-                            Map<String, String> newData = transformMap((Map<?, ?>) entry.getValue());
-                            newRow.putAll(newData);
-                            answer.add(newRow);
-                        }
-                    } else {
-                        // flattern each entry in the row as a list of single Map<key, value> elements
-                        Map<?, ?> newData = transformMap(row);
-                        for (Object obj : newData.entrySet()) {
-                            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
-                            Map<String, String> newRow = new LinkedHashMap<>();
-                            newRow.put(entry.getKey().toString(), entry.getValue().toString());
-                            answer.add(newRow);
-                        }
-                    }
-                }
-            }
-        } catch (Exception e) {
-            // wrap parsing exceptions as runtime
-            throw new RuntimeException("Cannot parse json", e);
-        }
-
-        return answer;
-    }
-
-    private static Map<String, String> transformMap(Map<?, ?> jsonMap) {
-        Map<String, String> answer = new LinkedHashMap<>();
-
-        for (Object rowObj : jsonMap.entrySet()) {
-            Map.Entry<?, ?> rowEntry = (Map.Entry<?, ?>) rowObj;
-            // if its a list type then its an enum, and we need to parse it as a single line separated with comma
-            // to be backwards compatible
-            Object newValue = rowEntry.getValue();
-            if (newValue instanceof List) {
-                List<?> list = (List<?>) newValue;
-                newValue = list.stream().map(Object::toString)
-                        .collect(Collectors.joining(","));
-            }
-            // ensure value is escaped
-            String value = escapeJson(newValue.toString());
-            answer.put(rowEntry.getKey().toString(), value);
-        }
-
-        return answer;
-    }
-
-    private static String escapeJson(String value) {
-        // need to safe encode \r as \\r so its escaped
-        // need to safe encode \n as \\n so its escaped
-        // need to safe encode \t as \\t so its escaped
-        return value
-            .replaceAll("\\\\r", "\\\\\\r")
-            .replaceAll("\\\\n", "\\\\\\n")
-            .replaceAll("\\\\t", "\\\\\\t");
-    }
-
-    /**
-     * Gets the value with the key in a safe way, eg returning an empty string if there was no value for the key.
-     */
-    public static String getSafeValue(String key, List<Map<String, String>> rows) {
-        for (Map<String, String> row : rows) {
-            String value = row.get(key);
-            if (value != null) {
-                return value;
-            }
-        }
-        return "";
-    }
-
-    /**
-     * Gets the value with the key in a safe way, eg returning an empty string if there was no value for the key.
-     */
-    public static String getSafeValue(String key, Map<String, String> rows) {
-        String value = rows.get(key);
-        if (value != null) {
-            return value;
-        }
-        return "";
-    }
-
-    public static String getPropertyDefaultValue(List<Map<String, String>> rows, String name) {
-        for (Map<String, String> row : rows) {
-            String defaultValue = null;
-            boolean found = false;
-            if (row.containsKey("name")) {
-                found = name.equals(row.get("name"));
-            }
-            if (row.containsKey("defaultValue")) {
-                defaultValue = row.get("defaultValue");
-            }
-            if (found) {
-                return defaultValue;
-            }
-        }
-        return null;
-    }
-
-    public static String getPropertyDescriptionValue(List<Map<String, String>> rows, String name) {
-        for (Map<String, String> row : rows) {
-            String description = null;
-            boolean found = false;
-            if (row.containsKey("name")) {
-                found = name.equals(row.get("name"));
-            }
-            if (row.containsKey("description")) {
-                description = row.get("description");
-            }
-            if (found) {
-                return description;
-            }
-        }
-        return null;
-    }
-
-    public static String getPropertyJavaType(List<Map<String, String>> rows, String name) {
-        for (Map<String, String> row : rows) {
-            String javaType = null;
-            boolean found = false;
-            if (row.containsKey("name")) {
-                found = name.equals(row.get("name"));
-            }
-            if (row.containsKey("javaType")) {
-                javaType = row.get("javaType");
-            }
-            if (found) {
-                return javaType;
-            }
-        }
-        return null;
-    }
-
-    public static String getPropertyType(List<Map<String, String>> rows, String name) {
-        for (Map<String, String> row : rows) {
-            String type = null;
-            boolean found = false;
-            if (row.containsKey("name")) {
-                found = name.equals(row.get("name"));
-            }
-            if (row.containsKey("type")) {
-                type = row.get("type");
-            }
-            if (found) {
-                return type;
-            }
-        }
-        return null;
-    }
-
-}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageArchetypeCatalogMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageArchetypeCatalogMojo.java
index b09cb74..77d44b3 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageArchetypeCatalogMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageArchetypeCatalogMojo.java
@@ -35,8 +35,8 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 
-import static org.apache.camel.maven.packaging.PackageHelper.findCamelDirectory;
-import static org.apache.camel.maven.packaging.StringHelper.between;
+import static org.apache.camel.tooling.util.Strings.between;
+import static org.apache.camel.tooling.util.PackageHelper.findCamelDirectory;
 
 /**
  * Creates the Maven catalog for the Camel archetypes
@@ -192,7 +192,7 @@ public class PackageArchetypeCatalogMojo extends AbstractMojo {
 
                     List<String> includes = new ArrayList<>();
                     includes.add("archetype-catalog.xml");
-                    projectHelper.addResource(project, outDir.getPath(), includes, new ArrayList<String>());
+                    projectHelper.addResource(project, outDir.getPath(), includes, new ArrayList<>());
                     projectHelper.attachArtifact(project, "xml", "archetype-catalog", out);
                 }
             } catch (Exception e) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageComponentMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageComponentMojo.java
index fb1253d..fd13e18 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageComponentMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageComponentMojo.java
@@ -17,13 +17,14 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
+import org.apache.camel.tooling.util.PackageHelper;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.logging.Log;
@@ -33,7 +34,7 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
 
 /**
  * Analyses the Camel plugins in a project and generates extra descriptor information for easier auto-discovery in Camel.
@@ -75,7 +76,7 @@ public class PackageComponentMojo extends AbstractGeneratorMojo {
             projectHelper.addResource(project, componentOutDir.getPath(), Collections.singletonList("**/component.properties"), Collections.emptyList());
         }
 
-        if (!PackageHelper.haveResourcesChanged(log, project, buildContext, "META-INF/services/org/apache/camel/component")) {
+        if (!haveResourcesChanged(log, project, buildContext, "META-INF/services/org/apache/camel/component")) {
             return 0;
         }
 
@@ -125,15 +126,15 @@ public class PackageComponentMojo extends AbstractGeneratorMojo {
     }
 
     private static void enrichComponentJsonFiles(Log log, MavenProject project, File buildDir, Set<String> components) throws MojoExecutionException {
-        final Set<File> files = PackageHelper.findJsonFiles(buildDir, p -> p.isDirectory() || p.getName().endsWith(".json"));
+        final Map<String, File> files = PackageHelper.findJsonFiles(buildDir, p -> p.isDirectory() || p.getName().endsWith(".json"));
 
-        for (File file : files) {
+        for (File file : files.values()) {
             // clip the .json suffix
             String name = file.getName().substring(0, file.getName().length() - 5);
             if (components.contains(name)) {
                 log.debug("Enriching component: " + name);
                 try {
-                    String text = loadText(new FileInputStream(file));
+                    String text = loadText(file);
                     text = text.replace("@@@DESCRIPTION@@@", project.getDescription());
                     text = text.replace("@@@GROUPID@@@", project.getGroupId());
                     text = text.replace("@@@ARTIFACTID@@@", project.getArtifactId());
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageDataFormatMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageDataFormatMojo.java
index ffdffb5..cba5a22 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageDataFormatMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageDataFormatMojo.java
@@ -17,15 +17,14 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.nio.file.Path;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.camel.tooling.util.JSonSchemaHelper;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.logging.Log;
@@ -35,10 +34,10 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import static org.apache.camel.maven.packaging.PackageHelper.after;
-import static org.apache.camel.maven.packaging.PackageHelper.findCamelCoreDirectory;
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.parseAsMap;
+import static org.apache.camel.tooling.util.PackageHelper.after;
+import static org.apache.camel.tooling.util.PackageHelper.findCamelCoreDirectory;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.parseAsMap;
 
 /**
  * Analyses the Camel plugins in a project and generates extra descriptor information for easier auto-discovery in Camel.
@@ -81,7 +80,7 @@ public class PackageDataFormatMojo extends AbstractGeneratorMojo {
             projectHelper.addResource(project, dataFormatOutDir.getPath(), Collections.singletonList("**/dataformat.properties"), Collections.emptyList());
         }
 
-        if (!PackageHelper.haveResourcesChanged(log, project, buildContext, "META-INF/services/org/apache/camel/dataformat")) {
+        if (!haveResourcesChanged(log, project, buildContext, "META-INF/services/org/apache/camel/dataformat")) {
             return 0;
         }
 
@@ -122,8 +121,7 @@ public class PackageDataFormatMojo extends AbstractGeneratorMojo {
                         String javaType = entry.getValue();
                         String modelName = asModelName(name);
 
-                        InputStream is = new FileInputStream(new File(core, "target/classes/org/apache/camel/model/dataformat/" + modelName + ".json"));
-                        String json = loadText(is);
+                        String json = loadText(new File(core, "target/classes/org/apache/camel/model/dataformat/" + modelName + ".json"));
 
                         DataFormatModel dataFormatModel = extractDataFormatModel(project, json, modelName, name, javaType);
                         if (log.isDebugEnabled()) {
@@ -173,7 +171,7 @@ public class PackageDataFormatMojo extends AbstractGeneratorMojo {
         return count;
     }
 
-    private static DataFormatModel extractDataFormatModel(MavenProject project, String json, String modelName, String name, String javaType) throws Exception {
+    private static DataFormatModel extractDataFormatModel(MavenProject project, String json, String modelName, String name, String javaType) {
         DataFormatModel dataFormatModel = new DataFormatModel();
         dataFormatModel.setName(name);
         dataFormatModel.setTitle("");
@@ -243,7 +241,6 @@ public class PackageDataFormatMojo extends AbstractGeneratorMojo {
         String jsonGson = "\"enum\": [ \"Gson\", \"Jackson\", \"Johnzon\", \"XStream\", \"Fastjson\" ], \"deprecated\": \"false\", \"secret\": \"false\", \"defaultValue\": \"Gson\"";
         String jsonJackson = "\"enum\": [ \"Gson\", \"Jackson\", \"Johnzon\", \"XStream\", \"Fastjson\" ], \"deprecated\": \"false\", \"secret\": \"false\", \"defaultValue\": \"Jackson\"";
         String jsonJohnzon = "\"enum\": [ \"Gson\", \"Jackson\", \"Johnzon\", \"XStream\", \"Fastjson\" ], \"deprecated\": \"false\", \"secret\": \"false\", \"defaultValue\": \"Johnzon\"";
-        String jsonXStream = "\"enum\": [ \"Gson\", \"Jackson\", \"Johnzon\", \"XStream\", \"Fastjson\" ], \"deprecated\": \"false\", \"secret\": \"false\", \"defaultValue\": \"XStream\"";
         String jsonFastjson = "\"enum\": [ \"Gson\", \"Jackson\", \"Johnzon\", \"XStream\", \"Fastjson\" ], \"deprecated\": \"false\", \"secret\": \"false\", \"defaultValue\": \"Fastjson\"";
 
         if ("json-gson".equals(name)) {
@@ -252,8 +249,6 @@ public class PackageDataFormatMojo extends AbstractGeneratorMojo {
             properties = properties.replace(json, jsonJackson);
         } else if ("json-johnzon".equals(name)) {
             properties = properties.replace(json, jsonJohnzon);
-        } else if ("json-xstream".equals(name)) {
-            properties = properties.replace(json, jsonXStream);
         } else if ("json-fastjson".equals(name)) {
             properties = properties.replace(json, jsonFastjson);
         }
@@ -300,7 +295,7 @@ public class PackageDataFormatMojo extends AbstractGeneratorMojo {
 
         // find out the javaType for each data format
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
             Map<String, String> map = parseAsMap(text);
             return map.get("class");
         } catch (IOException e) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java
index c928b439..586ea9f 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java
@@ -17,15 +17,15 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.nio.file.Path;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.camel.tooling.util.JSonSchemaHelper;
+import org.apache.camel.tooling.util.PackageHelper;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.logging.Log;
@@ -35,10 +35,10 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import static org.apache.camel.maven.packaging.PackageHelper.after;
-import static org.apache.camel.maven.packaging.PackageHelper.findCamelCoreDirectory;
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.parseAsMap;
+import static org.apache.camel.tooling.util.PackageHelper.after;
+import static org.apache.camel.tooling.util.PackageHelper.findCamelCoreDirectory;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.parseAsMap;
 
 /**
  * Analyses the Camel plugins in a project and generates extra descriptor information for easier auto-discovery in Camel.
@@ -87,7 +87,7 @@ public class PackageLanguageMojo extends AbstractGeneratorMojo {
             projectHelper.addResource(project, languageOutDir.getPath(), Collections.singletonList("**/language.properties"), Collections.emptyList());
         }
 
-        if (!PackageHelper.haveResourcesChanged(log, project, buildContext, "META-INF/services/org/apache/camel/language")) {
+        if (!haveResourcesChanged(log, project, buildContext, "META-INF/services/org/apache/camel/language")) {
             return 0;
         }
 
@@ -140,8 +140,7 @@ public class PackageLanguageMojo extends AbstractGeneratorMojo {
                         languageModel.setArtifactId(project.getArtifactId());
                         languageModel.setVersion(project.getVersion());
 
-                        InputStream is = new FileInputStream(new File(core, "src/main/schema/" + modelName + ".json"));
-                        String json = loadText(is);
+                        String json = loadText(new File(core, "src/main/schema/" + modelName + ".json"));
                         List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("model", json, false);
                         for (Map<String, String> row : rows) {
                             if (row.containsKey("title")) {
@@ -237,7 +236,7 @@ public class PackageLanguageMojo extends AbstractGeneratorMojo {
 
         // find out the javaType for each data format
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
             Map<String, String> map = parseAsMap(text);
             return map.get("class");
         } catch (IOException e) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageModelMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageModelMojo.java
index 5e3f89f..6084520 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageModelMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageModelMojo.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.apache.camel.tooling.util.PackageHelper;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.Mojo;
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java
index 6b44ce8..3cfb72e 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java
@@ -29,7 +29,7 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import static org.apache.camel.maven.packaging.StringHelper.camelDashToTitle;
+import static org.apache.camel.tooling.util.Strings.camelDashToTitle;
 
 /**
  * Analyses the Camel plugins in a project and generates extra descriptor information for easier auto-discovery in Camel.
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogKarafMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogKarafMojo.java
index 82573e1..a0c5c84 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogKarafMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogKarafMojo.java
@@ -19,14 +19,12 @@ package org.apache.camel.maven.packaging;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.Collections;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
 import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 
@@ -37,6 +35,7 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import org.apache.camel.tooling.util.FileUtil;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -46,7 +45,7 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
 import static org.w3c.dom.Node.ELEMENT_NODE;
 
 /**
@@ -55,8 +54,6 @@ import static org.w3c.dom.Node.ELEMENT_NODE;
 @Mojo(name = "prepare-catalog-karaf", threadSafe = true)
 public class PrepareCatalogKarafMojo extends AbstractMojo {
 
-    public static final int BUFFER_SIZE = 128 * 1024;
-
     /**
      * The maven project.
      */
@@ -184,44 +181,10 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
         getLog().info("Found " + componentFiles.size() + " component.properties files");
         getLog().info("Found " + jsonFiles.size() + " component json files");
 
-        // make sure to create out dir
-        componentsOutDir.mkdirs();
-
-        for (File file : jsonFiles) {
-            File to = new File(componentsOutDir, file.getName());
-            try {
-                copyFile(file, to);
-            } catch (IOException e) {
-                throw new MojoFailureException("Cannot copy file from " + file + " -> " + to, e);
-            }
-        }
-
-        File all = new File(componentsOutDir, "../components.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = componentsOutDir.list();
-            List<String> components = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String componentName = name.substring(0, name.length() - 5);
-                    components.add(componentName);
-                }
-            }
-
-            Collections.sort(components);
-            for (String name : components) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        // copy json files
+        Path outDir = componentsOutDir.toPath();
+        copyFiles(outDir, jsonFiles);
+        generateJsonList(outDir, "../components.properties");
     }
 
     protected void executeDataFormats(Set<String> features) throws MojoExecutionException, MojoFailureException {
@@ -263,44 +226,10 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
         getLog().info("Found " + dataFormatFiles.size() + " dataformat.properties files");
         getLog().info("Found " + jsonFiles.size() + " dataformat json files");
 
-        // make sure to create out dir
-        dataFormatsOutDir.mkdirs();
-
-        for (File file : jsonFiles) {
-            File to = new File(dataFormatsOutDir, file.getName());
-            try {
-                copyFile(file, to);
-            } catch (IOException e) {
-                throw new MojoFailureException("Cannot copy file from " + file + " -> " + to, e);
-            }
-        }
-
-        File all = new File(dataFormatsOutDir, "../dataformats.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = dataFormatsOutDir.list();
-            List<String> dataFormats = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String dataFormatName = name.substring(0, name.length() - 5);
-                    dataFormats.add(dataFormatName);
-                }
-            }
-
-            Collections.sort(dataFormats);
-            for (String name : dataFormats) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        // copy json files
+        Path outDir = dataFormatsOutDir.toPath();
+        copyFiles(outDir, jsonFiles);
+        generateJsonList(outDir, "../dataformats.properties");
     }
 
     protected void executeLanguages(Set<String> features) throws MojoExecutionException, MojoFailureException {
@@ -347,44 +276,10 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
         getLog().info("Found " + languageFiles.size() + " language.properties files");
         getLog().info("Found " + jsonFiles.size() + " language json files");
 
-        // make sure to create out dir
-        languagesOutDir.mkdirs();
-
-        for (File file : jsonFiles) {
-            File to = new File(languagesOutDir, file.getName());
-            try {
-                copyFile(file, to);
-            } catch (IOException e) {
-                throw new MojoFailureException("Cannot copy file from " + file + " -> " + to, e);
-            }
-        }
-
-        File all = new File(languagesOutDir, "../languages.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = languagesOutDir.list();
-            List<String> languages = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String languageName = name.substring(0, name.length() - 5);
-                    languages.add(languageName);
-                }
-            }
-
-            Collections.sort(languages);
-            for (String name : languages) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        // copy json files
+        Path outDir = languagesOutDir.toPath();
+        copyFiles(outDir, jsonFiles);
+        generateJsonList(outDir, "../languages.properties");
     }
 
     protected void executeOthers(Set<String> features) throws MojoExecutionException, MojoFailureException {
@@ -438,44 +333,10 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
         getLog().info("Found " + otherFiles.size() + " other.properties files");
         getLog().info("Found " + jsonFiles.size() + " other json files");
 
-        // make sure to create out dir
-        othersOutDir.mkdirs();
-
-        for (File file : jsonFiles) {
-            File to = new File(othersOutDir, file.getName());
-            try {
-                copyFile(file, to);
-            } catch (IOException e) {
-                throw new MojoFailureException("Cannot copy file from " + file + " -> " + to, e);
-            }
-        }
-
-        File all = new File(othersOutDir, "../others.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = othersOutDir.list();
-            List<String> others = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String otherName = name.substring(0, name.length() - 5);
-                    others.add(otherName);
-                }
-            }
-
-            Collections.sort(others);
-            for (String name : others) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        // copy json files
+        Path outDir = othersOutDir.toPath();
+        copyFiles(outDir, jsonFiles);
+        generateJsonList(outDir, "../others.properties");
     }
 
     private void findComponentFilesRecursive(File dir, Set<File> found, Set<File> components, FileFilter filter) {
@@ -554,7 +415,7 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
         }
     }
 
-    private class CamelComponentsFileFilter implements FileFilter {
+    private static class CamelComponentsFileFilter implements FileFilter {
 
         @Override
         public boolean accept(File pathname) {
@@ -565,17 +426,18 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a components json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
-                    return json != null && json.contains("\"kind\": \"component\"");
+                    String json = loadText(pathname);
+                    return json.contains("\"kind\": \"component\"");
                 } catch (IOException e) {
                     // ignore
                 }
             }
-            return pathname.isDirectory() || (pathname.isFile() && pathname.getName().equals("component.properties"));
+            return pathname.isDirectory()
+                    || (pathname.isFile() && pathname.getName().equals("component.properties"));
         }
     }
 
-    private class CamelDataFormatsFileFilter implements FileFilter {
+    private static class CamelDataFormatsFileFilter implements FileFilter {
 
         @Override
         public boolean accept(File pathname) {
@@ -586,17 +448,18 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a dataformat json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
-                    return json != null && json.contains("\"kind\": \"dataformat\"");
+                    String json = loadText(pathname);
+                    return json.contains("\"kind\": \"dataformat\"");
                 } catch (IOException e) {
                     // ignore
                 }
             }
-            return pathname.isDirectory() || (pathname.isFile() && pathname.getName().equals("dataformat.properties"));
+            return pathname.isDirectory()
+                    || (pathname.isFile() && pathname.getName().equals("dataformat.properties"));
         }
     }
 
-    private class CamelLanguagesFileFilter implements FileFilter {
+    private static class CamelLanguagesFileFilter implements FileFilter {
 
         @Override
         public boolean accept(File pathname) {
@@ -607,57 +470,68 @@ public class PrepareCatalogKarafMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a language json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
-                    return json != null && json.contains("\"kind\": \"language\"");
+                    String json = loadText(pathname);
+                    return json.contains("\"kind\": \"language\"");
                 } catch (IOException e) {
                     // ignore
                 }
             }
-            return pathname.isDirectory() || (pathname.isFile() && pathname.getName().equals("language.properties"));
+            return pathname.isDirectory()
+                    || (pathname.isFile() && pathname.getName().equals("language.properties"));
         }
     }
 
-    private class CamelOthersFileFilter implements FileFilter {
+    private static class CamelOthersFileFilter implements FileFilter {
 
         @Override
         public boolean accept(File pathname) {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a language json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
-                    return json != null && json.contains("\"kind\": \"other\"");
+                    String json = loadText(pathname);
+                    return json.contains("\"kind\": \"other\"");
                 } catch (IOException e) {
                     // ignore
                 }
             }
-            return pathname.isDirectory() || (pathname.isFile() && pathname.getName().equals("other.properties"));
+            return pathname.isDirectory()
+                    || (pathname.isFile() && pathname.getName().equals("other.properties"));
         }
     }
 
-    public static void copyFile(File from, File to) throws IOException {
-        FileChannel in = null;
-        FileChannel out = null;
-        try (FileInputStream fis = new FileInputStream(from); FileOutputStream fos = new FileOutputStream(to)) {
+    public static void copyFiles(Path outDir, Collection<File> files) throws MojoFailureException {
+        for (File file : files) {
+            Path to = outDir.resolve(file.getName());
             try {
-                in = fis.getChannel();
-                out = fos.getChannel();
-
-                long size = in.size();
-                long position = 0;
-                while (position < size) {
-                    position += in.transferTo(position, BUFFER_SIZE, out);
-                }
-            } finally {
-                if (in != null) {
-                    in.close();
-                }
-                if (out != null) {
-                    out.close();
-                }
+                FileUtil.updateFile(file.toPath(), to);
+            } catch (IOException e) {
+                throw new MojoFailureException("Cannot copy file from " + file + " -> " + to, e);
             }
         }
     }
 
+    public static Set<String> generateJsonList(Path outDir, String outFile) throws MojoFailureException {
+        Path all = outDir.resolve(outFile);
+        try {
+            Set<String> answer = Files.list(outDir)
+                    .filter(p -> p.getFileName().toString().endsWith(".json"))
+                    .map(p -> p.getFileName().toString())
+                    // strip out .json from the name
+                    .map(n -> n.substring(0, n.length() - ".json".length()))
+                    .sorted()
+                    .collect(LinkedHashSet::new, LinkedHashSet::add, LinkedHashSet::addAll);
+            String data = String.join("\n", answer) + "\n";
+            FileUtil.updateFile(all, data);
+            return answer;
+        } catch (IOException e) {
+            throw new MojoFailureException("Error writing to file " + all);
+        }
+    }
+
+    public static void copyFile(File from, File to) throws IOException {
+        FileUtil.updateFile(from.toPath(), to.toPath());
+    }
+
     private Set<String> findKarafFeatures() throws MojoExecutionException, MojoFailureException {
         // load features.xml file and parse it
 
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
index f602cad..3dc6cd3 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
@@ -18,12 +18,13 @@ package org.apache.camel.maven.packaging;
 
 import java.io.File;
 import java.io.FileFilter;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.channels.FileChannel;
 import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -35,6 +36,9 @@ import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.camel.tooling.util.FileUtil;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
+import org.apache.camel.tooling.util.PackageHelper;
 import org.apache.commons.io.FileUtils;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -47,7 +51,7 @@ import org.apache.maven.project.MavenProjectHelper;
 import org.asciidoctor.Asciidoctor;
 import org.asciidoctor.OptionsBuilder;
 
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
 
 /**
  * Prepares the camel catalog to include component, data format, and eip descriptors,
@@ -56,8 +60,6 @@ import static org.apache.camel.maven.packaging.PackageHelper.loadText;
 @Mojo(name = "prepare-catalog", threadSafe = true)
 public class PrepareCatalogMojo extends AbstractMojo {
 
-    public static final int BUFFER_SIZE = 128 * 1024;
-
     private static final String[] EXCLUDE_DOC_FILES = {
         "camel-core-osgi", "camel-core-xml",
         "camel-http-common", "camel-http-base", "camel-jetty-common",
@@ -262,7 +264,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
 
             try {
                 // check if we have a label as we want the eip to include labels
-                String text = loadText(new FileInputStream(file));
+                String text = loadText(file);
                 // just do a basic label check
                 if (text.contains("\"label\": \"\"")) {
                     missingLabels.add(file);
@@ -435,7 +437,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
 
             // check if we have a component label as we want the components to include labels
             try {
-                String text = loadText(new FileInputStream(file));
+                String text = loadText(file);
                 String name = asComponentName(file);
                 Matcher matcher = LABEL_PATTERN.matcher(text);
                 // grab the label, and remember it in the used labels
@@ -443,11 +445,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
                     String label = matcher.group(1);
                     String[] labels = label.split(",");
                     for (String s : labels) {
-                        Set<String> components = usedComponentLabels.get(s);
-                        if (components == null) {
-                            components = new TreeSet<>();
-                            usedComponentLabels.put(s, components);
-                        }
+                        Set<String> components = usedComponentLabels.computeIfAbsent(s, k -> new TreeSet<>());
                         components.add(name);
                     }
                 }
@@ -459,9 +457,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
 
                     if (label != null && !label.isEmpty()) {
                         String[] parts = label.split(",");
-                        for (String part : parts) {
-                            usedOptionLabels.add(part);
-                        }
+                        Collections.addAll(usedOptionLabels, parts);
                     }
                 }
 
@@ -472,9 +468,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
                     String label = row.get("label");
                     if (label != null && !label.isEmpty()) {
                         String[] parts = label.split(",");
-                        for (String part : parts) {
-                            usedOptionLabels.add(part);
-                        }
+                        usedOptionLabels.addAll(Arrays.asList(parts));
                     } else {
                         unused++;
                     }
@@ -490,11 +484,8 @@ public class PrepareCatalogMojo extends AbstractMojo {
                     String alternativeScheme = row.get("alternativeSchemes");
                     if (alternativeScheme != null && !alternativeScheme.isEmpty()) {
                         String[] parts = alternativeScheme.split(",");
-                        for (int i = 1; i < parts.length; i++) {
-                            // skip first as that is the regular scheme
-                            String part = parts[i];
-                            alternativeSchemes.add(part);
-                        }
+                        // skip first as that is the regular scheme
+                        alternativeSchemes.addAll(Arrays.asList(parts).subList(1, parts.length));
                     }
                 }
 
@@ -514,49 +505,14 @@ public class PrepareCatalogMojo extends AbstractMojo {
             }
         }
 
-        Set<String> componentNames = new LinkedHashSet<>();
-
-        File all = new File(componentsOutDir, "../components.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = componentsOutDir.list();
-            List<String> components = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String componentName = name.substring(0, name.length() - 5);
-                    components.add(componentName);
-                }
-            }
-
-            Collections.sort(components);
-            for (String name : components) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-
-                // remember component name
-                componentNames.add(name);
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        Set<String> componentNames =
+                generateJsonList(componentsOutDir.toPath(), "../components.properties");
 
         printComponentsReport(jsonFiles, duplicateJsonFiles, missingComponents, usedComponentLabels, usedOptionLabels, unlabeledOptions, missingFirstVersions);
 
         // filter out duplicate component names that are alternative scheme names
-        Set<String> answer = new LinkedHashSet<>();
-        for (String componentName : componentNames) {
-            if (!alternativeSchemes.contains(componentName)) {
-                answer.add(componentName);
-            }
-        }
-
-        return answer;
+        componentNames.removeAll(alternativeSchemes);
+        return componentNames;
     }
     // CHECKSTYLE:ON
 
@@ -625,7 +581,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
 
             // check if we have a label as we want the data format to include labels
             try {
-                String text = loadText(new FileInputStream(file));
+                String text = loadText(file);
                 String name = asComponentName(file);
                 Matcher matcher = LABEL_PATTERN.matcher(text);
                 // grab the label, and remember it in the used labels
@@ -633,11 +589,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
                     String label = matcher.group(1);
                     String[] labels = label.split(",");
                     for (String s : labels) {
-                        Set<String> dataFormats = usedLabels.get(s);
-                        if (dataFormats == null) {
-                            dataFormats = new TreeSet<>();
-                            usedLabels.put(s, dataFormats);
-                        }
+                        Set<String> dataFormats = usedLabels.computeIfAbsent(s, k -> new TreeSet<>());
                         dataFormats.add(name);
                     }
                 }
@@ -659,37 +611,8 @@ public class PrepareCatalogMojo extends AbstractMojo {
             }
         }
 
-        Set<String> answer = new LinkedHashSet<>();
-
-        File all = new File(dataFormatsOutDir, "../dataformats.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = dataFormatsOutDir.list();
-            List<String> dataFormats = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String dataFormatName = name.substring(0, name.length() - 5);
-                    dataFormats.add(dataFormatName);
-                }
-            }
-
-            Collections.sort(dataFormats);
-            for (String name : dataFormats) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-
-                // remember dataformat name
-                answer.add(name);
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        Set<String> answer =
+                generateJsonList(dataFormatsOutDir.toPath(), "../dataformats.properties");
 
         printDataFormatsReport(jsonFiles, duplicateJsonFiles, usedLabels, missingFirstVersions);
 
@@ -760,7 +683,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
 
             // check if we have a label as we want the data format to include labels
             try {
-                String text = loadText(new FileInputStream(file));
+                String text = loadText(file);
                 String name = asComponentName(file);
                 Matcher matcher = LABEL_PATTERN.matcher(text);
                 // grab the label, and remember it in the used labels
@@ -768,11 +691,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
                     String label = matcher.group(1);
                     String[] labels = label.split(",");
                     for (String s : labels) {
-                        Set<String> languages = usedLabels.get(s);
-                        if (languages == null) {
-                            languages = new TreeSet<>();
-                            usedLabels.put(s, languages);
-                        }
+                        Set<String> languages = usedLabels.computeIfAbsent(s, k -> new TreeSet<>());
                         languages.add(name);
                     }
                 }
@@ -794,37 +713,8 @@ public class PrepareCatalogMojo extends AbstractMojo {
             }
         }
 
-        Set<String> answer = new LinkedHashSet<>();
-
-        File all = new File(languagesOutDir, "../languages.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = languagesOutDir.list();
-            List<String> languages = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String languageName = name.substring(0, name.length() - 5);
-                    languages.add(languageName);
-                }
-            }
-
-            Collections.sort(languages);
-            for (String name : languages) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-
-                // remember language name
-                answer.add(name);
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        Set<String> answer =
+                generateJsonList(languagesOutDir.toPath(), "../languages.properties");
 
         printLanguagesReport(jsonFiles, duplicateJsonFiles, usedLabels, missingFirstVersions);
 
@@ -910,7 +800,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
 
             // check if we have a label as we want the other to include labels
             try {
-                String text = loadText(new FileInputStream(file));
+                String text = loadText(file);
                 String name = asComponentName(file);
                 Matcher matcher = LABEL_PATTERN.matcher(text);
                 // grab the label, and remember it in the used labels
@@ -918,11 +808,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
                     String label = matcher.group(1);
                     String[] labels = label.split(",");
                     for (String s : labels) {
-                        Set<String> others = usedLabels.get(s);
-                        if (others == null) {
-                            others = new TreeSet<>();
-                            usedLabels.put(s, others);
-                        }
+                        Set<String> others = usedLabels.computeIfAbsent(s, k -> new TreeSet<>());
                         others.add(name);
                     }
                 }
@@ -944,37 +830,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
             }
         }
 
-        Set<String> answer = new LinkedHashSet<>();
-
-        File all = new File(othersOutDir, "../others.properties");
-        try {
-            FileOutputStream fos = new FileOutputStream(all, false);
-
-            String[] names = othersOutDir.list();
-            List<String> others = new ArrayList<>();
-            // sort the names
-            for (String name : names) {
-                if (name.endsWith(".json")) {
-                    // strip out .json from the name
-                    String otherName = name.substring(0, name.length() - 5);
-                    others.add(otherName);
-                }
-            }
-
-            Collections.sort(others);
-            for (String name : others) {
-                fos.write(name.getBytes());
-                fos.write("\n".getBytes());
-
-                // remember other name
-                answer.add(name);
-            }
-
-            fos.close();
-
-        } catch (IOException e) {
-            throw new MojoFailureException("Error writing to file " + all);
-        }
+        Set<String> answer = generateJsonList(othersOutDir.toPath(), "../others.properties");
 
         printOthersReport(jsonFiles, duplicateJsonFiles, usedLabels, missingFirstVersions);
 
@@ -1640,7 +1496,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a components json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
+                    String json = loadText(pathname);
                     return json != null && json.contains("\"kind\": \"component\"");
                 } catch (IOException e) {
                     // ignore
@@ -1661,7 +1517,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a dataformat json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
+                    String json = loadText(pathname);
                     return json != null && json.contains("\"kind\": \"dataformat\"");
                 } catch (IOException e) {
                     // ignore
@@ -1682,7 +1538,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a language json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
+                    String json = loadText(pathname);
                     return json != null && json.contains("\"kind\": \"language\"");
                 } catch (IOException e) {
                     // ignore
@@ -1699,7 +1555,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a language json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
+                    String json = loadText(pathname);
                     return json != null && json.contains("\"kind\": \"other\"");
                 } catch (IOException e) {
                     // ignore
@@ -1717,30 +1573,29 @@ public class PrepareCatalogMojo extends AbstractMojo {
         }
     }
 
-    public static void copyFile(File from, File to) throws IOException {
-        FileChannel in = null;
-        FileChannel out = null;
-        try (FileInputStream fis = new FileInputStream(from); FileOutputStream fos = new FileOutputStream(to)) {
-            try {
-                in = fis.getChannel();
-                out = fos.getChannel();
-
-                long size = in.size();
-                long position = 0;
-                while (position < size) {
-                    position += in.transferTo(position, BUFFER_SIZE, out);
-                }
-            } finally {
-                if (in != null) {
-                    in.close();
-                }
-                if (out != null) {
-                    out.close();
-                }
-            }
+    public static Set<String> generateJsonList(Path outDir, String outFile) throws MojoFailureException {
+        Set<String> answer;
+        Path all = outDir.resolve(outFile);
+        try {
+            answer = Files.list(outDir)
+                    .filter(p -> p.getFileName().toString().endsWith(".json"))
+                    .map(p -> p.getFileName().toString())
+                    // strip out .json from the name
+                    .map(n -> n.substring(0, n.length() - ".json".length()))
+                    .sorted()
+                    .collect(LinkedHashSet::new, LinkedHashSet::add, LinkedHashSet::addAll);
+            String data = String.join("\n", answer) + "\n";
+            FileUtil.updateFile(all, data);
+            return answer;
+        } catch (IOException e) {
+            throw new MojoFailureException("Error writing to file " + all);
         }
     }
 
+    public static void copyFile(File from, File to) throws IOException {
+        FileUtil.updateFile(from.toPath(), to.toPath());
+    }
+
     private static boolean excludeDocumentDir(String name) {
         for (String exclude : EXCLUDE_DOC_FILES) {
             if (exclude.equals(name)) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java
index 78d151a..923f9dd 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java
@@ -17,7 +17,6 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.file.Paths;
@@ -32,6 +31,7 @@ import java.util.Set;
 import java.util.TreeSet;
 
 import org.apache.camel.maven.packaging.model.ExampleModel;
+import org.apache.camel.tooling.util.Strings;
 import org.apache.commons.io.FileUtils;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -43,8 +43,8 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.mvel2.templates.TemplateRuntime;
 
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.writeText;
 
 /**
  * Prepares the readme.md files content up to date with all the examples that Apache Camel ships.
@@ -104,10 +104,10 @@ public class PrepareExampleMojo extends AbstractMojo {
                         ExampleModel model = new ExampleModel();
                         model.setFileName(file.getName());
 
-                        String name = StringHelper.between(existing, "<name>", "</name>");
-                        String title = StringHelper.between(existing, "<title>", "</title>");
-                        String description = StringHelper.between(existing, "<description>", "</description>");
-                        String category = StringHelper.between(existing, "<category>", "</category>");
+                        String name = Strings.between(existing, "<name>", "</name>");
+                        String title = Strings.between(existing, "<title>", "</title>");
+                        String description = Strings.between(existing, "<description>", "</description>");
+                        String category = Strings.between(existing, "<category>", "</category>");
 
                         if (title != null) {
                             model.setTitle(title);
@@ -139,7 +139,7 @@ public class PrepareExampleMojo extends AbstractMojo {
             }
 
             // sort the models
-            Collections.sort(models, new ExampleComparator());
+            models.sort(new ExampleComparator());
 
             // how many deprecated
             long deprecated = models.stream()
@@ -186,9 +186,9 @@ public class PrepareExampleMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "// examples: START", "// examples: END");
+            String existing = Strings.between(text, "// examples: START", "// examples: END");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -196,8 +196,8 @@ public class PrepareExampleMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "// examples: START");
-                    String after = StringHelper.after(text, "// examples: END");
+                    String before = Strings.before(text, "// examples: START");
+                    String after = Strings.after(text, "// examples: END");
                     text = before + "// examples: START\n" + changed + "\n// examples: END" + after;
                     writeText(file, text);
                     return true;
@@ -234,7 +234,7 @@ public class PrepareExampleMojo extends AbstractMojo {
         if (answer.startsWith("camel-example-")) {
             answer = answer.substring(14);
         }
-        answer = StringHelper.camelDashToTitle(answer);
+        answer = Strings.camelDashToTitle(answer);
         return answer;
     }
 
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareParentPomMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareParentPomMojo.java
index 1f6ce8e..103a12b 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareParentPomMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareParentPomMojo.java
@@ -17,13 +17,13 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
+import org.apache.camel.tooling.util.Strings;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -33,10 +33,10 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 
-import static org.apache.camel.maven.packaging.PackageHelper.after;
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.writeText;
-import static org.apache.camel.maven.packaging.StringHelper.between;
+import static org.apache.camel.tooling.util.PackageHelper.after;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.Strings.between;
 
 /**
  * Prepares the parent/pom.xml to keep the Camel artifacts up-to-date.
@@ -131,7 +131,7 @@ public class PrepareParentPomMojo extends AbstractMojo {
     }
 
     private String asArtifactId(File pom) throws IOException {
-        String text = loadText(new FileInputStream(pom));
+        String text = loadText(pom);
         text = after(text, "</parent>");
         if (text != null) {
             text = between(text, "<artifactId>", "</artifactId>");
@@ -149,7 +149,7 @@ public class PrepareParentPomMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
             String existing = between(text, start, end);
             if (existing != null) {
@@ -159,8 +159,8 @@ public class PrepareParentPomMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, start);
-                    String after = StringHelper.after(text, end);
+                    String before = Strings.before(text, start);
+                    String after = Strings.after(text, end);
                     text = before + start + "\n      " + changed + "\n      " + end + after;
                     writeText(file, text);
                     return true;
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReleasePomMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReleasePomMojo.java
index 56fe00a..5874462 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReleasePomMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReleasePomMojo.java
@@ -17,13 +17,13 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
+import org.apache.camel.tooling.util.Strings;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -33,10 +33,10 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 
-import static org.apache.camel.maven.packaging.PackageHelper.after;
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.writeText;
-import static org.apache.camel.maven.packaging.StringHelper.between;
+import static org.apache.camel.tooling.util.PackageHelper.after;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.Strings.between;
 
 /**
  * Prepares the apache-camel/pom.xml and common-bin to keep the Camel artifacts up-to-date.
@@ -153,10 +153,10 @@ public class PrepareReleasePomMojo extends AbstractMojo {
     }
 
     private String asArtifactId(File pom) throws IOException {
-        String text = loadText(new FileInputStream(pom));
+        String text = loadText(pom);
         text = after(text, "</parent>");
         if (text != null) {
-            return between(text, "<artifactId>", "</artifactId>");
+            return Strings.between(text, "<artifactId>", "</artifactId>");
         }
         return null;
     }
@@ -174,7 +174,7 @@ public class PrepareReleasePomMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
             String existing = between(text, start, end);
             if (existing != null) {
@@ -184,8 +184,8 @@ public class PrepareReleasePomMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, start);
-                    String after = StringHelper.after(text, end);
+                    String before = Strings.before(text, start);
+                    String after = Strings.after(text, end);
                     text = before + start + "\n" + spaces + changed + "\n" + spaces + end + after;
                     writeText(file, text);
                     return true;
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareUserGuideMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareUserGuideMojo.java
index b5409bb..75f14c4 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareUserGuideMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareUserGuideMojo.java
@@ -17,7 +17,6 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -32,6 +31,8 @@ import org.apache.camel.maven.packaging.model.ComponentModel;
 import org.apache.camel.maven.packaging.model.DataFormatModel;
 import org.apache.camel.maven.packaging.model.LanguageModel;
 import org.apache.camel.maven.packaging.model.OtherModel;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
+import org.apache.camel.tooling.util.Strings;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -41,8 +42,10 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.getSafeValue;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.parseJsonSchema;
 
 /**
  * Prepares the user guide to keep the table of content up to date with the components, data formats, and languages.
@@ -120,7 +123,7 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         try {
             List<ComponentModel> models = new ArrayList<>();
             for (File file : componentFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 ComponentModel model = generateComponentModel(json);
 
                 // filter out alternative schemas which reuses documentation
@@ -188,7 +191,7 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         try {
             List<OtherModel> models = new ArrayList<>();
             for (File file : otherFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 OtherModel model = generateOtherModel(json);
                 models.add(model);
             }
@@ -232,7 +235,7 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         try {
             List<DataFormatModel> models = new ArrayList<>();
             for (File file : dataFormatFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 DataFormatModel model = generateDataFormatModel(json);
                 models.add(model);
             }
@@ -276,7 +279,7 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         try {
             List<LanguageModel> models = new ArrayList<>();
             for (File file : languageFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 LanguageModel model = generateLanguageModel(json);
                 models.add(model);
             }
@@ -313,9 +316,9 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "<!-- core components: START -->", "<!-- core components: END -->");
+            String existing = Strings.between(text, "<!-- core components: START -->", "<!-- core components: END -->");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -323,8 +326,8 @@ public class PrepareUserGuideMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "<!-- core components: START -->");
-                    String after = StringHelper.after(text, "<!-- core components: END -->");
+                    String before = Strings.before(text, "<!-- core components: START -->");
+                    String after = Strings.after(text, "<!-- core components: END -->");
                     text = before + "<!-- core components: START -->\n" + changed + "\n<!-- core components: END -->" + after;
                     writeText(file, text);
                     return true;
@@ -347,9 +350,9 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "<!-- components: START -->", "<!-- components: END -->");
+            String existing = Strings.between(text, "<!-- components: START -->", "<!-- components: END -->");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -357,8 +360,8 @@ public class PrepareUserGuideMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "<!-- components: START -->");
-                    String after = StringHelper.after(text, "<!-- components: END -->");
+                    String before = Strings.before(text, "<!-- components: START -->");
+                    String after = Strings.after(text, "<!-- components: END -->");
                     text = before + "<!-- components: START -->\n" + changed + "\n<!-- components: END -->" + after;
                     writeText(file, text);
                     return true;
@@ -381,9 +384,9 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "<!-- others: START -->", "<!-- others: END -->");
+            String existing = Strings.between(text, "<!-- others: START -->", "<!-- others: END -->");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -391,8 +394,8 @@ public class PrepareUserGuideMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "<!-- others: START -->");
-                    String after = StringHelper.after(text, "<!-- others: END -->");
+                    String before = Strings.before(text, "<!-- others: START -->");
+                    String after = Strings.after(text, "<!-- others: END -->");
                     text = before + "<!-- others: START -->\n" + changed + "\n<!-- others: END -->" + after;
                     writeText(file, text);
                     return true;
@@ -415,9 +418,9 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "<!-- dataformats: START -->", "<!-- dataformats: END -->");
+            String existing = Strings.between(text, "<!-- dataformats: START -->", "<!-- dataformats: END -->");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -425,8 +428,8 @@ public class PrepareUserGuideMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "<!-- dataformats: START -->");
-                    String after = StringHelper.after(text, "<!-- dataformats: END -->");
+                    String before = Strings.before(text, "<!-- dataformats: START -->");
+                    String after = Strings.after(text, "<!-- dataformats: END -->");
                     text = before + "<!-- dataformats: START -->\n" + changed + "\n<!-- dataformats: END -->" + after;
                     writeText(file, text);
                     return true;
@@ -449,9 +452,9 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "<!-- languages: START -->", "<!-- languages: END -->");
+            String existing = Strings.between(text, "<!-- languages: START -->", "<!-- languages: END -->");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -459,8 +462,8 @@ public class PrepareUserGuideMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "<!-- languages: START -->");
-                    String after = StringHelper.after(text, "<!-- languages: END -->");
+                    String before = Strings.before(text, "<!-- languages: START -->");
+                    String after = Strings.after(text, "<!-- languages: END -->");
                     text = before + "<!-- languages: START -->\n" + changed + "\n<!-- languages: END -->" + after;
                     writeText(file, text);
                     return true;
@@ -541,25 +544,25 @@ public class PrepareUserGuideMojo extends AbstractMojo {
     }
 
     private ComponentModel generateComponentModel(String json) {
-        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("component", json, false);
+        List<Map<String, String>> rows = parseJsonSchema("component", json, false);
 
         ComponentModel component = new ComponentModel();
-        component.setScheme(JSonSchemaHelper.getSafeValue("scheme", rows));
-        component.setSyntax(JSonSchemaHelper.getSafeValue("syntax", rows));
-        component.setAlternativeSyntax(JSonSchemaHelper.getSafeValue("alternativeSyntax", rows));
-        component.setAlternativeSchemes(JSonSchemaHelper.getSafeValue("alternativeSchemes", rows));
-        component.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        component.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        component.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        component.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        component.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        component.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        component.setConsumerOnly(JSonSchemaHelper.getSafeValue("consumerOnly", rows));
-        component.setProducerOnly(JSonSchemaHelper.getSafeValue("producerOnly", rows));
-        component.setJavaType(JSonSchemaHelper.getSafeValue("javaType", rows));
-        component.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        component.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        component.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        component.setScheme(getSafeValue("scheme", rows));
+        component.setSyntax(getSafeValue("syntax", rows));
+        component.setAlternativeSyntax(getSafeValue("alternativeSyntax", rows));
+        component.setAlternativeSchemes(getSafeValue("alternativeSchemes", rows));
+        component.setTitle(getSafeValue("title", rows));
+        component.setDescription(getSafeValue("description", rows));
+        component.setFirstVersion(getSafeValue("firstVersion", rows));
+        component.setLabel(getSafeValue("label", rows));
+        component.setDeprecated(getSafeValue("deprecated", rows));
+        component.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        component.setConsumerOnly(getSafeValue("consumerOnly", rows));
+        component.setProducerOnly(getSafeValue("producerOnly", rows));
+        component.setJavaType(getSafeValue("javaType", rows));
+        component.setGroupId(getSafeValue("groupId", rows));
+        component.setArtifactId(getSafeValue("artifactId", rows));
+        component.setVersion(getSafeValue("version", rows));
 
         return component;
     }
@@ -568,16 +571,16 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("other", json, false);
 
         OtherModel other = new OtherModel();
-        other.setName(JSonSchemaHelper.getSafeValue("name", rows));
-        other.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        other.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        other.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        other.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        other.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        other.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        other.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        other.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        other.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        other.setName(getSafeValue("name", rows));
+        other.setTitle(getSafeValue("title", rows));
+        other.setDescription(getSafeValue("description", rows));
+        other.setFirstVersion(getSafeValue("firstVersion", rows));
+        other.setLabel(getSafeValue("label", rows));
+        other.setDeprecated(getSafeValue("deprecated", rows));
+        other.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        other.setGroupId(getSafeValue("groupId", rows));
+        other.setArtifactId(getSafeValue("artifactId", rows));
+        other.setVersion(getSafeValue("version", rows));
 
         return other;
     }
@@ -586,18 +589,18 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("dataformat", json, false);
 
         DataFormatModel dataFormat = new DataFormatModel();
-        dataFormat.setName(JSonSchemaHelper.getSafeValue("name", rows));
-        dataFormat.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        dataFormat.setModelName(JSonSchemaHelper.getSafeValue("modelName", rows));
-        dataFormat.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        dataFormat.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        dataFormat.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        dataFormat.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        dataFormat.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        dataFormat.setJavaType(JSonSchemaHelper.getSafeValue("javaType", rows));
-        dataFormat.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        dataFormat.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        dataFormat.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        dataFormat.setName(getSafeValue("name", rows));
+        dataFormat.setTitle(getSafeValue("title", rows));
+        dataFormat.setModelName(getSafeValue("modelName", rows));
+        dataFormat.setDescription(getSafeValue("description", rows));
+        dataFormat.setFirstVersion(getSafeValue("firstVersion", rows));
+        dataFormat.setLabel(getSafeValue("label", rows));
+        dataFormat.setDeprecated(getSafeValue("deprecated", rows));
+        dataFormat.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        dataFormat.setJavaType(getSafeValue("javaType", rows));
+        dataFormat.setGroupId(getSafeValue("groupId", rows));
+        dataFormat.setArtifactId(getSafeValue("artifactId", rows));
+        dataFormat.setVersion(getSafeValue("version", rows));
 
         return dataFormat;
     }
@@ -606,18 +609,18 @@ public class PrepareUserGuideMojo extends AbstractMojo {
         List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("language", json, false);
 
         LanguageModel language = new LanguageModel();
-        language.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        language.setName(JSonSchemaHelper.getSafeValue("name", rows));
-        language.setModelName(JSonSchemaHelper.getSafeValue("modelName", rows));
-        language.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        language.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        language.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        language.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        language.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        language.setJavaType(JSonSchemaHelper.getSafeValue("javaType", rows));
-        language.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        language.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        language.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        language.setTitle(getSafeValue("title", rows));
+        language.setName(getSafeValue("name", rows));
+        language.setModelName(getSafeValue("modelName", rows));
+        language.setDescription(getSafeValue("description", rows));
+        language.setFirstVersion(getSafeValue("firstVersion", rows));
+        language.setLabel(getSafeValue("label", rows));
+        language.setDeprecated(getSafeValue("deprecated", rows));
+        language.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        language.setJavaType(getSafeValue("javaType", rows));
+        language.setGroupId(getSafeValue("groupId", rows));
+        language.setArtifactId(getSafeValue("artifactId", rows));
+        language.setVersion(getSafeValue("version", rows));
 
         return language;
     }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java
deleted file mode 100644
index 468c115..0000000
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.util.Collection;
-
-import com.google.common.base.CaseFormat;
-
-public final class StringHelper {
-
-    private StringHelper() {
-        // Utils Class
-    }
-
-    public static boolean isEmpty(String s) {
-        return s == null || s.trim().isEmpty();
-    }
-
-    public static String after(String text, String after) {
-        if (!text.contains(after)) {
-            return null;
-        }
-        return text.substring(text.indexOf(after) + after.length());
-    }
-
-    public static String before(String text, String before) {
-        if (!text.contains(before)) {
-            return null;
-        }
-        return text.substring(0, text.indexOf(before));
-    }
-
-    public static String between(String text, String after, String before) {
-        text = after(text, after);
-        if (text == null) {
-            return null;
-        }
-        return before(text, before);
-    }
-
-    public static String indentCollection(String indent, Collection<String> list) {
-        StringBuilder sb = new StringBuilder();
-        for (String text : list) {
-            sb.append(indent).append(text);
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Converts the value to use title style instead of dash cased
-     */
-    public static String camelDashToTitle(String value) {
-        StringBuilder sb = new StringBuilder(value.length());
-        boolean dash = false;
-
-        for (char c : value.toCharArray()) {
-            if ('-' == c) {
-                dash = true;
-                continue;
-            }
-
-            if (dash) {
-                sb.append(' ');
-                sb.append(Character.toUpperCase(c));
-            } else {
-                // upper case first
-                if (sb.length() == 0) {
-                    sb.append(Character.toUpperCase(c));
-                } else {
-                    sb.append(c);
-                }
-            }
-            dash = false;
-        }
-        return sb.toString();
-    }
-
-    public static String cutLastZeroDigit(String version) {
-        String answer = version;
-        // cut last digit so its not 2.18.0 but 2.18
-        String[] parts = version.split("\\.");
-        if (parts.length == 3 && parts[2].equals("0")) {
-            answer = parts[0] + "." + parts[1];
-        }
-        return answer;
-    }
-
-    /**
-     * To wrap long camel cased texts by words.
-     *
-     * @param option  the option which is camel cased.
-     * @param watermark a watermark to denote the size to cut after
-     * @param newLine the new line to use when breaking into a new line
-     */
-    public static String wrapCamelCaseWords(String option, int watermark, String newLine) {
-        String text = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, option);
-        text = text.replace('-', ' ');
-        text = wrapWords(text, "\n", watermark, false);
-        text = text.replace(' ', '-');
-        text = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, text);
-
-        // upper case first char on each line
-        String[] lines = text.split("\n");
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < lines.length; i++) {
-            String line = lines[i];
-            line = Character.toUpperCase(line.charAt(0)) + line.substring(1);
-            sb.append(line);
-            if (i < lines.length - 1) {
-                sb.append(newLine);
-            }
-        }
-        return sb.toString();
-    }
-
-    /**
-     * To wrap a big line by words.
-     *
-     * @param line the big line
-     * @param newLine the new line to use when breaking into a new line
-     * @param watermark a watermark to denote the size to cut after
-     * @param wrapLongWords whether to wrap long words
-     */
-    public static String wrapWords(String line, String newLine, int watermark, boolean wrapLongWords) {
-        if (line == null) {
-            return null;
-        } else {
-            if (newLine == null) {
-                newLine = System.lineSeparator();
-            }
-
-            if (watermark < 1) {
-                watermark = 1;
-            }
-
-            int inputLineLength = line.length();
-            int offset = 0;
-            StringBuilder sb = new StringBuilder(inputLineLength + 32);
-
-            while (inputLineLength - offset > watermark) {
-                if (line.charAt(offset) == 32) {
-                    ++offset;
-                } else {
-                    int spaceToWrapAt = line.lastIndexOf(32, watermark + offset);
-                    if (spaceToWrapAt >= offset) {
-                        sb.append(line.substring(offset, spaceToWrapAt));
-                        sb.append(newLine);
-                        offset = spaceToWrapAt + 1;
-                    } else if (wrapLongWords) {
-                        sb.append(line.substring(offset, watermark + offset));
-                        sb.append(newLine);
-                        offset += watermark;
-                    } else {
-                        spaceToWrapAt = line.indexOf(32, watermark + offset);
-                        if (spaceToWrapAt >= 0) {
-                            sb.append(line.substring(offset, spaceToWrapAt));
-                            sb.append(newLine);
-                            offset = spaceToWrapAt + 1;
-                        } else {
-                            sb.append(line.substring(offset));
-                            offset = inputLineLength;
-                        }
-                    }
-                }
-            }
-
-            sb.append(line.substring(offset));
-            return sb.toString();
-        }
-    }
-
-    /**
-     * Returns the base class name, i.e. without package and generic related
-     * information.
-     * 
-     * @param className The class name which base class is to be computed.
-     * @return the base class name, i.e. without package and generic related
-     *         information.
-     */
-    public static String getClassShortName(String className) {
-        if (className != null) {
-            return className.replaceAll("<.*>", "").replaceAll(".*[.]([^.]+)", "$1");
-        }
-        return className;
-    }
-}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateDocComponentListMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateDocComponentListMojo.java
index 0a2834e..36c7cce 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateDocComponentListMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateDocComponentListMojo.java
@@ -17,7 +17,6 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -34,6 +33,7 @@ import org.apache.camel.maven.packaging.model.DataFormatModel;
 import org.apache.camel.maven.packaging.model.EipModel;
 import org.apache.camel.maven.packaging.model.LanguageModel;
 import org.apache.camel.maven.packaging.model.OtherModel;
+import org.apache.camel.tooling.util.Strings;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -44,9 +44,10 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.mvel2.templates.TemplateRuntime;
 
-import static java.util.stream.Collectors.toSet;
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.getSafeValue;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.parseJsonSchema;
 
 /**
  * Updates the website docs with the component list to be up to date with all the artifacts that Apache Camel ships.
@@ -124,7 +125,7 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         try {
             List<ComponentModel> models = new ArrayList<>();
             for (File file : componentFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 ComponentModel model = generateComponentModel(json);
 
                 // filter out alternative schemas which reuses documentation
@@ -147,12 +148,13 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
             }
 
             // sort the models
-            Collections.sort(models, new ComponentComparator());
+            models.sort(new ComponentComparator());
 
             // how many different artifacts
-            int count = models.stream()
+            long count = models.stream()
                     .map(ComponentModel::getArtifactId)
-                    .collect(toSet()).size();
+                    .distinct()
+                    .count();
 
             // how many deprecated
             long deprecated = models.stream()
@@ -189,18 +191,19 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         try {
             List<OtherModel> others = new ArrayList<>();
             for (File file : otherFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 OtherModel model = generateOtherModel(json);
                 others.add(model);
             }
 
             // sort the models
-            Collections.sort(others, new OtherComparator());
+            others.sort(new OtherComparator());
 
             // how many different artifacts
-            int count = others.stream()
+            long count = others.stream()
                     .map(OtherModel::getArtifactId)
-                    .collect(toSet()).size();
+                    .distinct()
+                    .count();
 
             // how many deprecated
             long deprecated = others.stream()
@@ -238,7 +241,7 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         try {
             List<DataFormatModel> models = new ArrayList<>();
             for (File file : dataFormatFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 DataFormatModel model = generateDataFormatModel(json);
 
                 // special for bindy as we have one common file
@@ -250,12 +253,13 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
             }
 
             // sort the models
-            Collections.sort(models, new DataFormatComparator());
+            models.sort(new DataFormatComparator());
 
             // how many different artifacts
-            int count = models.stream()
+            long count = models.stream()
                     .map(DataFormatModel::getArtifactId)
-                    .collect(toSet()).size();
+                    .distinct()
+                    .count();
 
             // how many deprecated
             long deprecated = models.stream()
@@ -293,18 +297,19 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         try {
             List<LanguageModel> models = new ArrayList<>();
             for (File file : languageFiles) {
-                String json = loadText(new FileInputStream(file));
+                String json = loadText(file);
                 LanguageModel model = generateLanguageModel(json);
                 models.add(model);
             }
 
             // sort the models
-            Collections.sort(models, new LanguageComparator());
+            models.sort(new LanguageComparator());
 
             // how many different artifacts
-            int count = models.stream()
+            long count = models.stream()
                     .map(LanguageModel::getArtifactId)
-                    .collect(toSet()).size();
+                    .distinct()
+                    .count();
 
             // how many deprecated
             long deprecated = models.stream()
@@ -329,9 +334,9 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
     }
 
-    private String templateComponents(List<ComponentModel> models, int artifacts, long deprecated) throws MojoExecutionException {
+    private String templateComponents(List<ComponentModel> models, long artifacts, long deprecated) throws MojoExecutionException {
         try {
-            String template = loadText(UpdateReadmeMojo.class.getClassLoader().getResourceAsStream("website-components-list.mvel"));
+            String template = loadResource("website-components-list.mvel");
             Map<String, Object> map = new HashMap<>();
             map.put("components", models);
             map.put("numberOfArtifacts", artifacts);
@@ -343,9 +348,9 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
     }
 
-    private String templateOthers(List<OtherModel> models, int artifacts, long deprecated) throws MojoExecutionException {
+    private String templateOthers(List<OtherModel> models, long artifacts, long deprecated) throws MojoExecutionException {
         try {
-            String template = loadText(UpdateReadmeMojo.class.getClassLoader().getResourceAsStream("website-others-list.mvel"));
+            String template = loadResource("website-others-list.mvel");
             Map<String, Object> map = new HashMap<>();
             map.put("others", models);
             map.put("numberOfArtifacts", artifacts);
@@ -357,9 +362,9 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
     }
 
-    private String templateDataFormats(List<DataFormatModel> models, int artifacts, long deprecated) throws MojoExecutionException {
+    private String templateDataFormats(List<DataFormatModel> models, long artifacts, long deprecated) throws MojoExecutionException {
         try {
-            String template = loadText(UpdateReadmeMojo.class.getClassLoader().getResourceAsStream("website-dataformats-list.mvel"));
+            String template = loadResource("website-dataformats-list.mvel");
             Map<String, Object> map = new HashMap<>();
             map.put("dataformats", models);
             map.put("numberOfArtifacts", artifacts);
@@ -371,9 +376,9 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
     }
 
-    private String templateLanguages(List<LanguageModel> models, int artifacts, long deprecated) throws MojoExecutionException {
+    private String templateLanguages(List<LanguageModel> models, long artifacts, long deprecated) throws MojoExecutionException {
         try {
-            String template = loadText(UpdateReadmeMojo.class.getClassLoader().getResourceAsStream("website-languages-list.mvel"));
+            String template = loadResource("website-languages-list.mvel");
             Map<String, Object> map = new HashMap<>();
             map.put("languages", models);
             map.put("numberOfArtifacts", artifacts);
@@ -385,15 +390,19 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
     }
 
+    private String loadResource(String name) throws IOException {
+        return loadText(UpdateReadmeMojo.class.getClassLoader().getResourceAsStream(name));
+    }
+
     private boolean updateComponents(File file, String changed) throws MojoExecutionException {
         if (!file.exists()) {
             return false;
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "// components: START", "// components: END");
+            String existing = Strings.between(text, "// components: START", "// components: END");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -401,8 +410,8 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "// components: START");
-                    String after = StringHelper.after(text, "// components: END");
+                    String before = Strings.before(text, "// components: START");
+                    String after = Strings.after(text, "// components: END");
                     text = before + "// components: START\n" + changed + "\n// components: END" + after;
                     writeText(file, text);
                     return true;
@@ -425,9 +434,9 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "// others: START", "// others: END");
+            String existing = Strings.between(text, "// others: START", "// others: END");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -435,8 +444,8 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "// others: START");
-                    String after = StringHelper.after(text, "// others: END");
+                    String before = Strings.before(text, "// others: START");
+                    String after = Strings.after(text, "// others: END");
                     text = before + "// others: START\n" + changed + "\n// others: END" + after;
                     writeText(file, text);
                     return true;
@@ -459,9 +468,9 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "// dataformats: START", "// dataformats: END");
+            String existing = Strings.between(text, "// dataformats: START", "// dataformats: END");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -469,8 +478,8 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "// dataformats: START");
-                    String after = StringHelper.after(text, "// dataformats: END");
+                    String before = Strings.before(text, "// dataformats: START");
+                    String after = Strings.after(text, "// dataformats: END");
                     text = before + "// dataformats: START\n" + changed + "\n// dataformats: END" + after;
                     writeText(file, text);
                     return true;
@@ -493,9 +502,9 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
         }
 
         try {
-            String text = loadText(new FileInputStream(file));
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "// languages: START", "// languages: END");
+            String existing = Strings.between(text, "// languages: START", "// languages: END");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -503,8 +512,8 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
                 if (existing.equals(changed)) {
                     return false;
                 } else {
-                    String before = StringHelper.before(text, "// languages: START");
-                    String after = StringHelper.after(text, "// languages: END");
+                    String before = Strings.before(text, "// languages: START");
+                    String after = Strings.after(text, "// languages: END");
                     text = before + "// languages: START\n" + changed + "\n// languages: END" + after;
                     writeText(file, text);
                     return true;
@@ -567,100 +576,100 @@ public class UpdateDocComponentListMojo extends AbstractMojo {
     }
 
     private EipModel generateEipModel(String json) {
-        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("model", json, false);
+        List<Map<String, String>> rows = parseJsonSchema("model", json, false);
 
         EipModel eip = new EipModel();
-        eip.setName(JSonSchemaHelper.getSafeValue("name", rows));
-        eip.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        eip.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        eip.setJavaType(JSonSchemaHelper.getSafeValue("javaType", rows));
-        eip.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        eip.setDeprecated("true".equals(JSonSchemaHelper.getSafeValue("deprecated", rows)));
-        eip.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        eip.setInput("true".equals(JSonSchemaHelper.getSafeValue("input", rows)));
-        eip.setOutput("true".equals(JSonSchemaHelper.getSafeValue("output", rows)));
+        eip.setName(getSafeValue("name", rows));
+        eip.setTitle(getSafeValue("title", rows));
+        eip.setDescription(getSafeValue("description", rows));
+        eip.setJavaType(getSafeValue("javaType", rows));
+        eip.setLabel(getSafeValue("label", rows));
+        eip.setDeprecated("true".equals(getSafeValue("deprecated", rows)));
+        eip.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        eip.setInput("true".equals(getSafeValue("input", rows)));
+        eip.setOutput("true".equals(getSafeValue("output", rows)));
 
         return eip;
     }
 
     private ComponentModel generateComponentModel(String json) {
-        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("component", json, false);
+        List<Map<String, String>> rows = parseJsonSchema("component", json, false);
 
         ComponentModel component = new ComponentModel();
-        component.setScheme(JSonSchemaHelper.getSafeValue("scheme", rows));
-        component.setSyntax(JSonSchemaHelper.getSafeValue("syntax", rows));
-        component.setAlternativeSyntax(JSonSchemaHelper.getSafeValue("alternativeSyntax", rows));
-        component.setAlternativeSchemes(JSonSchemaHelper.getSafeValue("alternativeSchemes", rows));
-        component.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        component.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        component.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        component.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        component.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        component.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        component.setConsumerOnly(JSonSchemaHelper.getSafeValue("consumerOnly", rows));
-        component.setProducerOnly(JSonSchemaHelper.getSafeValue("producerOnly", rows));
-        component.setJavaType(JSonSchemaHelper.getSafeValue("javaType", rows));
-        component.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        component.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        component.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        component.setScheme(getSafeValue("scheme", rows));
+        component.setSyntax(getSafeValue("syntax", rows));
+        component.setAlternativeSyntax(getSafeValue("alternativeSyntax", rows));
+        component.setAlternativeSchemes(getSafeValue("alternativeSchemes", rows));
+        component.setTitle(getSafeValue("title", rows));
+        component.setDescription(getSafeValue("description", rows));
+        component.setFirstVersion(getSafeValue("firstVersion", rows));
+        component.setLabel(getSafeValue("label", rows));
+        component.setDeprecated(getSafeValue("deprecated", rows));
+        component.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        component.setConsumerOnly(getSafeValue("consumerOnly", rows));
+        component.setProducerOnly(getSafeValue("producerOnly", rows));
+        component.setJavaType(getSafeValue("javaType", rows));
+        component.setGroupId(getSafeValue("groupId", rows));
+        component.setArtifactId(getSafeValue("artifactId", rows));
+        component.setVersion(getSafeValue("version", rows));
 
         return component;
     }
 
     private OtherModel generateOtherModel(String json) {
-        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("other", json, false);
+        List<Map<String, String>> rows = parseJsonSchema("other", json, false);
 
         OtherModel other = new OtherModel();
-        other.setName(JSonSchemaHelper.getSafeValue("name", rows));
-        other.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        other.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        other.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        other.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        other.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        other.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        other.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        other.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        other.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        other.setName(getSafeValue("name", rows));
+        other.setTitle(getSafeValue("title", rows));
+        other.setDescription(getSafeValue("description", rows));
+        other.setFirstVersion(getSafeValue("firstVersion", rows));
+        other.setLabel(getSafeValue("label", rows));
+        other.setDeprecated(getSafeValue("deprecated", rows));
+        other.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        other.setGroupId(getSafeValue("groupId", rows));
+        other.setArtifactId(getSafeValue("artifactId", rows));
+        other.setVersion(getSafeValue("version", rows));
 
         return other;
     }
 
     private DataFormatModel generateDataFormatModel(String json) {
-        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("dataformat", json, false);
+        List<Map<String, String>> rows = parseJsonSchema("dataformat", json, false);
 
         DataFormatModel dataFormat = new DataFormatModel();
-        dataFormat.setName(JSonSchemaHelper.getSafeValue("name", rows));
-        dataFormat.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        dataFormat.setModelName(JSonSchemaHelper.getSafeValue("modelName", rows));
-        dataFormat.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        dataFormat.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        dataFormat.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        dataFormat.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        dataFormat.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        dataFormat.setJavaType(JSonSchemaHelper.getSafeValue("javaType", rows));
-        dataFormat.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        dataFormat.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        dataFormat.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        dataFormat.setName(getSafeValue("name", rows));
+        dataFormat.setTitle(getSafeValue("title", rows));
+        dataFormat.setModelName(getSafeValue("modelName", rows));
+        dataFormat.setDescription(getSafeValue("description", rows));
+        dataFormat.setFirstVersion(getSafeValue("firstVersion", rows));
+        dataFormat.setLabel(getSafeValue("label", rows));
+        dataFormat.setDeprecated(getSafeValue("deprecated", rows));
+        dataFormat.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        dataFormat.setJavaType(getSafeValue("javaType", rows));
+        dataFormat.setGroupId(getSafeValue("groupId", rows));
+        dataFormat.setArtifactId(getSafeValue("artifactId", rows));
+        dataFormat.setVersion(getSafeValue("version", rows));
 
         return dataFormat;
     }
 
     private LanguageModel generateLanguageModel(String json) {
-        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("language", json, false);
+        List<Map<String, String>> rows = parseJsonSchema("language", json, false);
 
         LanguageModel language = new LanguageModel();
-        language.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
-        language.setName(JSonSchemaHelper.getSafeValue("name", rows));
-        language.setModelName(JSonSchemaHelper.getSafeValue("modelName", rows));
-        language.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
-        language.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
-        language.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
-        language.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
-        language.setDeprecationNote(JSonSchemaHelper.getSafeValue("deprecationNote", rows));
-        language.setJavaType(JSonSchemaHelper.getSafeValue("javaType", rows));
-        language.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
-        language.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
-        language.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+        language.setTitle(getSafeValue("title", rows));
+        language.setName(getSafeValue("name", rows));
+        language.setModelName(getSafeValue("modelName", rows));
+        language.setDescription(getSafeValue("description", rows));
+        language.setFirstVersion(getSafeValue("firstVersion", rows));
+        language.setLabel(getSafeValue("label", rows));
+        language.setDeprecated(getSafeValue("deprecated", rows));
+        language.setDeprecationNote(getSafeValue("deprecationNote", rows));
+        language.setJavaType(getSafeValue("javaType", rows));
+        language.setGroupId(getSafeValue("groupId", rows));
+        language.setArtifactId(getSafeValue("artifactId", rows));
+        language.setVersion(getSafeValue("version", rows));
 
         return language;
     }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java
index e0bec70..bce8cb1 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java
@@ -17,7 +17,6 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Paths;
@@ -39,6 +38,8 @@ import org.apache.camel.maven.packaging.model.EipOptionModel;
 import org.apache.camel.maven.packaging.model.EndpointOptionModel;
 import org.apache.camel.maven.packaging.model.LanguageModel;
 import org.apache.camel.maven.packaging.model.LanguageOptionModel;
+import org.apache.camel.tooling.util.PackageHelper;
+import org.apache.camel.tooling.util.Strings;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Component;
@@ -48,11 +49,11 @@ import org.apache.maven.project.MavenProject;
 import org.mvel2.templates.TemplateRuntime;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import static org.apache.camel.maven.packaging.JSonSchemaHelper.getSafeValue;
-import static org.apache.camel.maven.packaging.JSonSchemaHelper.parseJsonSchema;
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.PackageHelper.writeText;
-import static org.apache.camel.maven.packaging.StringHelper.isEmpty;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.getSafeValue;
+import static org.apache.camel.tooling.util.JSonSchemaHelper.parseJsonSchema;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.PackageHelper.writeText;
+import static org.apache.camel.tooling.util.Strings.isEmpty;
 
 /**
  * Generate or updates the component/dataformat/language/eip readme.md and .adoc files in the project root directory.
@@ -381,10 +382,9 @@ public class UpdateReadmeMojo extends AbstractMojo {
 
         boolean updated = false;
 
-        try (InputStream fileStream = new FileInputStream(file)) {
+        try {
             List<String> newLines = new ArrayList<>();
-
-            String text = loadText(fileStream);
+            String text = loadText(file);
             String[] lines = text.split("\n");
             for (int i = 0; i < lines.length; i++) {
                 String line = lines[i];
@@ -422,10 +422,10 @@ public class UpdateReadmeMojo extends AbstractMojo {
 
         boolean updated = false;
 
-        try (InputStream fileStream = new FileInputStream(file)) {
+        try {
             List<String> newLines = new ArrayList<>();
 
-            String text = loadText(fileStream);
+            String text = loadText(file);
             String[] lines = text.split("\n");
             // line 0 is the link
             for (int i = 1; i < lines.length; i++) {
@@ -490,10 +490,10 @@ public class UpdateReadmeMojo extends AbstractMojo {
 
         final String headerText = generateHeaderTextData(model);
 
-        try (InputStream fileStream = new FileInputStream(file)) {
-            final String loadedText = loadText(fileStream);
+        try {
+            final String loadedText = loadText(file);
 
-            String existing = StringHelper.between(loadedText, markerStart, markerEnd);
+            String existing = Strings.between(loadedText, markerStart, markerEnd);
 
             if (existing != null) {
                 // remove leading line breaks etc
@@ -502,8 +502,8 @@ public class UpdateReadmeMojo extends AbstractMojo {
                     return false;
                 }
 
-                final String before = StringHelper.before(loadedText, markerStart);
-                final String after = StringHelper.after(loadedText, markerEnd);
+                final String before = Strings.before(loadedText, markerStart);
+                final String after = Strings.after(loadedText, markerEnd);
                 final String updatedHeaderText = before + markerStart + "\n" + headerText + "\n" + markerEnd + after;
 
                 writeText(file, updatedHeaderText);
@@ -511,8 +511,8 @@ public class UpdateReadmeMojo extends AbstractMojo {
             } else {
                 // so we don't have the marker, so we add it somewhere after the camel version
                 final String sinceVersion = "*Since Camel " + shortenVersion(model.getFirstVersion()) + "*";
-                final String before = StringHelper.before(loadedText, sinceVersion);
-                final String after = StringHelper.after(loadedText, sinceVersion);
+                final String before = Strings.before(loadedText, sinceVersion);
+                final String after = Strings.after(loadedText, sinceVersion);
                 final String updatedHeaderText = before + sinceVersion + "\n\n" + markerStart + "\n" + headerText + "\n" + markerEnd + after;
 
                 writeText(file, updatedHeaderText);
@@ -547,8 +547,8 @@ public class UpdateReadmeMojo extends AbstractMojo {
 
         boolean updated = false;
 
-        try (InputStream fileStream = new FileInputStream(file)) {
-            String text = loadText(fileStream);
+        try {
+            String text = loadText(file);
 
             String[] lines = text.split("\n");
 
@@ -613,10 +613,10 @@ public class UpdateReadmeMojo extends AbstractMojo {
         }
 
         final String updated = changed.trim();
-        try (InputStream fileStream = new FileInputStream(file)) {
-            String text = loadText(fileStream);
+        try {
+            String text = loadText(file);
 
-            String existing = StringHelper.between(text, "// " + kind + " options: START", "// " + kind + " options: END");
+            String existing = Strings.between(text, "// " + kind + " options: START", "// " + kind + " options: END");
             if (existing != null) {
                 // remove leading line breaks etc
                 existing = existing.trim();
@@ -624,8 +624,8 @@ public class UpdateReadmeMojo extends AbstractMojo {
                     return false;
                 }
 
-                String before = StringHelper.before(text, "// " + kind  + " options: START");
-                String after = StringHelper.after(text, "// " + kind + " options: END");
+                String before = Strings.before(text, "// " + kind  + " options: START");
+                String after = Strings.after(text, "// " + kind + " options: END");
                 text = before + "// " + kind + " options: START\n" + updated + "\n// " + kind + " options: END" + after;
                 writeText(file, text);
                 return true;
@@ -647,8 +647,8 @@ public class UpdateReadmeMojo extends AbstractMojo {
     private static String loadJsonFrom(Set<File> jsonFiles, String kind, String name) {
         for (File file : jsonFiles) {
             if (file.getName().equals(name + ".json")) {
-                try (InputStream fileStream = new FileInputStream(file)) {
-                    String json = loadText(fileStream);
+                try {
+                    String json = loadText(file);
                     boolean isRequestedKind = json.contains("\"kind\": \"" + kind + "\"");
                     if (isRequestedKind) {
                         return json;
@@ -663,8 +663,8 @@ public class UpdateReadmeMojo extends AbstractMojo {
     }
 
     private static String loadEipJson(File file) {
-        try (InputStream fileStream = new FileInputStream(file)) {
-            String json = loadText(fileStream);
+        try {
+            String json = loadText(file);
             boolean isEip = json.contains("\"kind\": \"model\"");
             if (isEip) {
                 return json;
@@ -722,7 +722,7 @@ public class UpdateReadmeMojo extends AbstractMojo {
             if ("true".equals(option.getDeprecated())) {
                 String desc = "*Deprecated* " + option.getDescription();
                 option.setDescription(desc);
-                if (!StringHelper.isEmpty(option.getDeprecationNote())) {
+                if (!Strings.isEmpty(option.getDeprecationNote())) {
                     desc = option.getDescription();
                     if (!desc.endsWith(".")) {
                         desc = desc + ". Deprecation note: " + option.getDeprecationNote();
@@ -769,7 +769,7 @@ public class UpdateReadmeMojo extends AbstractMojo {
             if ("true".equals(option.getDeprecated())) {
                 String desc = "*Deprecated* " + option.getDescription();
                 option.setDescription(desc);
-                if (!StringHelper.isEmpty(option.getDeprecationNote())) {
+                if (!Strings.isEmpty(option.getDeprecationNote())) {
                     desc = option.getDescription();
                     if (!desc.endsWith(".")) {
                         desc = desc + ". Deprecation note: " + option.getDeprecationNote();
@@ -838,7 +838,7 @@ public class UpdateReadmeMojo extends AbstractMojo {
             if ("true".equals(option.getDeprecated())) {
                 String desc = "*Deprecated* " + option.getDescription();
                 option.setDescription(desc);
-                if (!StringHelper.isEmpty(option.getDeprecationNote())) {
+                if (!Strings.isEmpty(option.getDeprecationNote())) {
                     desc = option.getDescription();
                     if (!desc.endsWith(".")) {
                         desc = desc + ". Deprecation note: " + option.getDeprecationNote();
@@ -895,7 +895,7 @@ public class UpdateReadmeMojo extends AbstractMojo {
             if ("true".equals(option.getDeprecated())) {
                 String desc = "*Deprecated* " + option.getDescription();
                 option.setDescription(desc);
-                if (!StringHelper.isEmpty(option.getDeprecationNote())) {
+                if (!Strings.isEmpty(option.getDeprecationNote())) {
                     desc = option.getDescription();
                     if (!desc.endsWith(".")) {
                         desc = desc + ". Deprecation note: " + option.getDeprecationNote();
@@ -955,7 +955,7 @@ public class UpdateReadmeMojo extends AbstractMojo {
             if (option.isDeprecated()) {
                 String desc = "*Deprecated* " + option.getDescription();
                 option.setDescription(desc);
-                if (!StringHelper.isEmpty(option.getDeprecationNote())) {
+                if (!Strings.isEmpty(option.getDeprecationNote())) {
                     desc = option.getDescription();
                     if (!desc.endsWith(".")) {
                         desc = desc + ". Deprecation note: " + option.getDeprecationNote();
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateComponentMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateComponentMojo.java
index c660a1f..deb896f 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateComponentMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateComponentMojo.java
@@ -18,11 +18,11 @@ package org.apache.camel.maven.packaging;
 
 import java.io.File;
 import java.io.FileFilter;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.apache.camel.tooling.util.PackageHelper;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -33,8 +33,8 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
-import static org.apache.camel.maven.packaging.StringHelper.indentCollection;
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
+import static org.apache.camel.tooling.util.Strings.indentCollection;
 import static org.apache.camel.maven.packaging.ValidateHelper.asName;
 import static org.apache.camel.maven.packaging.ValidateHelper.validate;
 
@@ -150,8 +150,8 @@ public class ValidateComponentMojo extends AbstractMojo {
             if (pathname.isFile() && pathname.getName().endsWith(".json")) {
                 // must be a components json file
                 try {
-                    String json = loadText(new FileInputStream(pathname));
-                    return json != null && json.contains("\"kind\": \"component\"");
+                    String json = loadText(pathname);
+                    return json.contains("\"kind\": \"component\"");
                 } catch (IOException e) {
                     // ignore
                 }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateHelper.java
index 5309af8..72c1851 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateHelper.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ValidateHelper.java
@@ -17,12 +17,14 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
-import static org.apache.camel.maven.packaging.PackageHelper.loadText;
+import org.apache.camel.tooling.util.JSonSchemaHelper;
+import org.apache.camel.tooling.util.Strings;
+
+import static org.apache.camel.tooling.util.PackageHelper.loadText;
 
 /**
  * Validation helper for validating components, data formats and languages
@@ -40,7 +42,7 @@ public final class ValidateHelper {
      */
     public static void validate(File file, ErrorDetail errorDetail) {
         try {
-            String json = loadText(new FileInputStream(file));
+            String json = loadText(file);
 
             boolean isComponent = json.contains("\"kind\": \"component\"");
             boolean isDataFormat = json.contains("\"kind\": \"dataformat\"");
@@ -65,15 +67,15 @@ public final class ValidateHelper {
             boolean syntax = false;
             for (Map<String, String> row : rows) {
                 String value = row.get("label");
-                if (!StringHelper.isEmpty(value)) {
+                if (!Strings.isEmpty(value)) {
                     label = true;
                 }
                 value = row.get("description");
-                if (!StringHelper.isEmpty(value)) {
+                if (!Strings.isEmpty(value)) {
                     description = true;
                 }
                 value = row.get("syntax");
-                if (!StringHelper.isEmpty(value)) {
+                if (!Strings.isEmpty(value)) {
                     syntax = true;
                 }
             }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentModel.java
index 6d87840..5cd1cea 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentModel.java
@@ -19,9 +19,9 @@ package org.apache.camel.maven.packaging.model;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.cutLastZeroDigit;
+import static org.apache.camel.tooling.util.Strings.cutLastZeroDigit;
 
 public class ComponentModel {
 
@@ -207,7 +207,7 @@ public class ComponentModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     public String getFirstVersionShort() {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentOptionModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentOptionModel.java
index 1fafbdb..1ea7a71 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentOptionModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/ComponentOptionModel.java
@@ -16,9 +16,9 @@
  */
 package org.apache.camel.maven.packaging.model;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.wrapCamelCaseWords;
+import static org.apache.camel.tooling.util.Strings.wrapCamelCaseWords;
 
 public class ComponentOptionModel {
 
@@ -152,13 +152,13 @@ public class ComponentOptionModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     @Deprecated
     public String getShortJavaType(int watermark) {
 
-        String text = StringHelper.getClassShortName(javaType);
+        String text = Strings.getClassShortName(javaType);
 
         // if its some kind of java object then lets wrap it as its long
         if ("object".equals(type)) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatModel.java
index b6dfd82..a6dbd58 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatModel.java
@@ -19,9 +19,9 @@ package org.apache.camel.maven.packaging.model;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.cutLastZeroDigit;
+import static org.apache.camel.tooling.util.Strings.cutLastZeroDigit;
 
 public class DataFormatModel {
 
@@ -153,7 +153,7 @@ public class DataFormatModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     public String getFirstVersionShort() {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatOptionModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatOptionModel.java
index d209a00..9dd5dee 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatOptionModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/DataFormatOptionModel.java
@@ -16,7 +16,7 @@
  */
 package org.apache.camel.maven.packaging.model;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
 public class DataFormatOptionModel {
 
@@ -112,7 +112,7 @@ public class DataFormatOptionModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
 }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EipOptionModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EipOptionModel.java
index 64c4a33..5e2ee91 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EipOptionModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EipOptionModel.java
@@ -16,9 +16,9 @@
  */
 package org.apache.camel.maven.packaging.model;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.wrapCamelCaseWords;
+import static org.apache.camel.tooling.util.Strings.wrapCamelCaseWords;
 
 public class EipOptionModel {
 
@@ -149,13 +149,13 @@ public class EipOptionModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     @Deprecated
     public String getShortJavaType(int watermark) {
 
-        String text = StringHelper.getClassShortName(javaType);
+        String text = Strings.getClassShortName(javaType);
 
         // if its some kind of java object then lets wrap it as its long
         if ("object".equals(type)) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EndpointOptionModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EndpointOptionModel.java
index 754d06a..068786e 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EndpointOptionModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/EndpointOptionModel.java
@@ -16,9 +16,9 @@
  */
 package org.apache.camel.maven.packaging.model;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.wrapCamelCaseWords;
+import static org.apache.camel.tooling.util.Strings.wrapCamelCaseWords;
 
 public class EndpointOptionModel {
 
@@ -188,13 +188,13 @@ public class EndpointOptionModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     @Deprecated
     public String getShortJavaType(int watermark) {
 
-        String text = StringHelper.getClassShortName(javaType);
+        String text = Strings.getClassShortName(javaType);
 
         // if its some kind of java object then lets wrap it as its long
         if ("object".equals(type)) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageModel.java
index ac47855..d57d03f 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageModel.java
@@ -19,9 +19,9 @@ package org.apache.camel.maven.packaging.model;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.cutLastZeroDigit;
+import static org.apache.camel.tooling.util.Strings.cutLastZeroDigit;
 
 public class LanguageModel {
 
@@ -153,7 +153,7 @@ public class LanguageModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     public String getFirstVersionShort() {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageOptionModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageOptionModel.java
index db7b015..bbd696f 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageOptionModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/LanguageOptionModel.java
@@ -16,7 +16,7 @@
  */
 package org.apache.camel.maven.packaging.model;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
 public class LanguageOptionModel {
 
@@ -112,7 +112,7 @@ public class LanguageOptionModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
 }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java
index e51941c..234aa28 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java
@@ -19,9 +19,9 @@ package org.apache.camel.maven.packaging.model;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.cutLastZeroDigit;
+import static org.apache.camel.tooling.util.Strings.cutLastZeroDigit;
 
 public class OtherModel {
 
@@ -148,6 +148,6 @@ public class OtherModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherOptionModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherOptionModel.java
index 1ac49e3..b7af1c7 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherOptionModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherOptionModel.java
@@ -16,9 +16,9 @@
  */
 package org.apache.camel.maven.packaging.model;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.wrapCamelCaseWords;
+import static org.apache.camel.tooling.util.Strings.wrapCamelCaseWords;
 
 public class OtherOptionModel {
 
@@ -152,13 +152,13 @@ public class OtherOptionModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     @Deprecated
     public String getShortJavaType(int watermark) {
 
-        String text = StringHelper.getClassShortName(javaType);
+        String text = Strings.getClassShortName(javaType);
 
         // if its some kind of java object then lets wrap it as its long
         if ("object".equals(type)) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/SpringBootAutoConfigureOptionModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/SpringBootAutoConfigureOptionModel.java
index 958527b..d07f627 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/SpringBootAutoConfigureOptionModel.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/SpringBootAutoConfigureOptionModel.java
@@ -16,9 +16,9 @@
  */
 package org.apache.camel.maven.packaging.model;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 
-import static org.apache.camel.maven.packaging.StringHelper.wrapCamelCaseWords;
+import static org.apache.camel.tooling.util.Strings.wrapCamelCaseWords;
 
 public class SpringBootAutoConfigureOptionModel {
 
@@ -60,13 +60,13 @@ public class SpringBootAutoConfigureOptionModel {
     }
 
     public String getShortJavaType() {
-        return StringHelper.getClassShortName(javaType);
+        return Strings.getClassShortName(javaType);
     }
 
     @Deprecated
     public String getShortJavaType(int watermark) {
 
-        String text = StringHelper.getClassShortName(javaType);
+        String text = Strings.getClassShortName(javaType);
 
         // if its some kind of custom java object then lets wrap it as its long
         if (!javaType.startsWith("java.")) {
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel
index 8165777..3fdc729 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel
@@ -8,6 +8,6 @@ The @{title} component supports @{componentOptions.size()} options, which are li
 [width="100%",cols="2,5,^1,2",options="header"]
 |===@comment{ Render table cells. If description contains newline, prefix cell with `a`, so the content is rendered with formatting. }
 | Name | Description | Default | Type
-@foreach{row : componentOptions}| *@{row.getShortName(25)}* (@{row.shortGroup}) @{row.description.?contains("\n") ? "a" : ""}| @{util.escape(row.description)} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType()}
+@foreach{row : componentOptions}| *@{row.getShortName(30)}* (@{row.shortGroup}) @{row.description.?contains("\n") ? "a" : ""}| @{util.escape(row.description)} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType()}
 @end{}|===
 @end{}
diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/model/StringHelperTest.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/model/StringHelperTest.java
index e13144a..560f91f 100644
--- a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/model/StringHelperTest.java
+++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/model/StringHelperTest.java
@@ -18,7 +18,7 @@ package org.apache.camel.maven.packaging.model;
 
 import java.util.stream.Stream;
 
-import org.apache.camel.maven.packaging.StringHelper;
+import org.apache.camel.tooling.util.Strings;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -46,6 +46,6 @@ public class StringHelperTest {
     @ParameterizedTest
     @MethodSource("getClassShortNameTypeVarations")
     public void getClassShortName(String expectedBaseClassName, String className) {
-        Assertions.assertEquals(expectedBaseClassName, StringHelper.getClassShortName(className));
+        Assertions.assertEquals(expectedBaseClassName, Strings.getClassShortName(className));
     }
 }
diff --git a/tooling/pom.xml b/tooling/pom.xml
index 52eb485..d1d0f9c 100644
--- a/tooling/pom.xml
+++ b/tooling/pom.xml
@@ -39,6 +39,7 @@
         <module>spi-annotations</module>
         <module>apt</module>
         <module>camel-util-json</module>
+        <module>camel-tooling-util</module>
         <module>camel-bundle-plugin</module>
         <module>swagger-rest-dsl-generator</module>
         <module>openapi-rest-dsl-generator</module>