You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2024/06/20 10:25:08 UTC

(camel-karaf) branch 361/add-camel-upgrade-tool created (now e4d4f06a)

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

nfilotto pushed a change to branch 361/add-camel-upgrade-tool
in repository https://gitbox.apache.org/repos/asf/camel-karaf.git


      at e4d4f06a Ref #361: Add a Camel upgrade tool

This branch includes the following new commits:

     new e4d4f06a Ref #361: Add a Camel upgrade tool

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(camel-karaf) 01/01: Ref #361: Add a Camel upgrade tool

Posted by nf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nfilotto pushed a commit to branch 361/add-camel-upgrade-tool
in repository https://gitbox.apache.org/repos/asf/camel-karaf.git

commit e4d4f06a607d7c67476db53d88a4b3c8a49f1f6b
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Mon Jun 17 16:44:15 2024 +0200

    Ref #361: Add a Camel upgrade tool
---
 components/camel-blueprint/pom.xml                 |   2 -
 components/pom.xml                                 |   4 +-
 pom.xml                                            |  15 +-
 tooling/camel-karaf-feature-maven-plugin/pom.xml   |   1 -
 tooling/camel-upgrade/README.md                    |  45 +++++
 tooling/camel-upgrade/camel-upgrade.properties     |  20 ++
 tooling/camel-upgrade/pom.xml                      |  90 +++++++++
 .../karaf/tooling/upgrade/ComponentComparator.java | 114 +++++++++++
 .../tooling/upgrade/DefaultValuesProvider.java     |  76 +++++++
 .../karaf/tooling/upgrade/FeatureHandler.java      | 113 +++++++++++
 .../tooling/upgrade/MultiModuleWrapperHandler.java |  94 +++++++++
 .../karaf/tooling/upgrade/ParentPomUpdater.java    | 151 ++++++++++++++
 .../camel/karaf/tooling/upgrade/PomUpdater.java    |  74 +++++++
 .../upgrade/SingleModuleWrapperHandler.java        |  87 ++++++++
 .../camel/karaf/tooling/upgrade/UpgradeCamel.java  | 221 +++++++++++++++++++++
 .../karaf/tooling/upgrade/UserInputProvider.java   | 117 +++++++++++
 .../apache/camel/karaf/tooling/upgrade/Utils.java  |  57 ++++++
 .../karaf/tooling/upgrade/WrapperHandler.java      | 136 +++++++++++++
 .../src/main/resources/log4j2.properties           |  21 ++
 .../main/resources/multi-module-parent-pom.xml}    |  24 ++-
 .../src/main/resources/multi-module-pom.xml        |  81 ++++++++
 .../src/main/resources/single-module-pom.xml       |  81 ++++++++
 .../tooling/upgrade/ComponentComparatorTest.java   | 108 ++++++++++
 .../tooling/upgrade/DefaultValuesProviderTest.java |  60 ++++++
 .../karaf/tooling/upgrade/FeatureHandlerTest.java  | 100 ++++++++++
 .../upgrade/MultiModuleWrapperHandlerTest.java     |  74 +++++++
 .../tooling/upgrade/ParentPomUpdaterTest.java      |  77 +++++++
 .../karaf/tooling/upgrade/PomUpdaterTest.java      |  47 +++++
 .../upgrade/SingleModuleWrapperHandlerTest.java    |  68 +++++++
 .../camel-both-multiple-a/.gitkeep                 |   0
 .../camel-both-multiple-b/.gitkeep                 |   0
 .../camel-karaf/camel-both-multiple/src/.gitkeep   |   0
 .../camel-karaf/camel-both-single/.gitkeep         |   0
 .../camel-karaf-multiple-a/.gitkeep                |   0
 .../camel-karaf-multiple-b/.gitkeep                |   0
 .../camel-karaf-multiple-only/.gitkeep             |   0
 .../comparator/camel-karaf/camel-karaf-only/.keep  |   0
 .../camel-multiple/camel-multiple-a/.gitkeep       |   0
 .../camel-multiple/camel-multiple-b/.gitkeep       |   0
 .../camel-both-multiple-a/.gitkeep                 |   0
 .../camel-both-multiple-b/.gitkeep                 |   0
 .../comparator/camel/camel-both-single/.gitkeep    |   0
 .../camel-complex-multiple-a/.gitkeep              |   0
 .../camel-complex-multiple-api/.gitkeep            |   0
 .../camel-complex-multiple-b/.gitkeep              |   0
 .../camel-complex-multiple-codegen/.gitkeep        |   0
 .../camel-complex-multiple-component/.gitkeep      |   0
 .../camel-complex-multiple-maven-plugin/.gitkeep   |   0
 .../camel-complex-multiple-spi/.gitkeep            |   0
 .../camel-complex-single-api/.gitkeep              |   0
 .../camel-complex-single-codegen/.gitkeep          |   0
 .../camel-complex-single-component/.gitkeep        |   0
 .../camel-complex-single-maven-plugin/.gitkeep     |   0
 .../camel-complex-single-spi/.gitkeep              |   0
 .../camel-karaf-multiple-a/.gitkeep                |   0
 .../camel-karaf-multiple-b/.gitkeep                |   0
 .../camel/camel-multiple/camel-multiple-a/.gitkeep |   0
 .../camel/camel-multiple/camel-multiple-b/.gitkeep |   0
 .../camel-multiple/camel-multiple-only/.gitkeep    |   0
 .../resources/comparator/camel/camel-only/.gitkeep |   0
 .../test/resources/comparator/camel/src/.gitkeep   |   0
 .../test/resources/default-values/empty.properties |   0
 .../test/resources/default-values/full.properties  |  20 ++
 .../src/test/resources/features/empty.xml          |   0
 .../resources/features/inject-after-expected.xml   |  59 ++++++
 .../src/test/resources/features/inject-after.xml   |  55 +++++
 .../resources/features/inject-before-expected.xml  |  59 ++++++
 .../src/test/resources/features/inject-before.xml  |  55 +++++
 .../resources/features/inject-middle-expected.xml  |  59 ++++++
 .../src/test/resources/features/inject-middle.xml  |  55 +++++
 .../resources/features/remove-after-expected.xml   |  55 +++++
 .../src/test/resources/features/remove-after.xml   |  61 ++++++
 .../resources/features/remove-before-expected.xml  |  55 +++++
 .../src/test/resources/features/remove-before.xml  |  61 ++++++
 .../resources/features/remove-middle-expected.xml  |  55 +++++
 .../src/test/resources/features/remove-middle.xml  |  61 ++++++
 .../camel-karaf/b-pom-after-remove-expected.xml}   |  24 ++-
 .../camel-karaf/b-pom-expected.xml}                |  26 ++-
 .../camel-karaf/b1-pom-expected.xml                |  81 ++++++++
 .../camel-karaf/expected-pom.xml}                  |  24 ++-
 .../multi-module-wrapper/camel-karaf}/pom.xml      |  23 ++-
 .../resources/multi-module-wrapper/camel/.gitkeep  |   0
 .../camel-karaf-pom-expected.xml                   |  78 ++++++++
 .../camel-karaf-pom-no-camel-start.xml             |  72 +++++++
 .../parent-pom-updater/camel-karaf-pom-no-end.xml  |  71 +++++++
 .../camel-karaf-pom-no-start.xml                   |  71 +++++++
 .../parent-pom-updater/camel-karaf-pom.xml         |  72 +++++++
 .../parent-pom-updater/camel-pom-no-start.xml      |  68 +++++++
 .../resources/parent-pom-updater/camel-pom.xml     |  73 +++++++
 .../resources/pom-updater/level2/level3}/pom.xml   |  42 ++--
 .../src/test/resources/pom-updater/level2}/pom.xml |  42 ++--
 .../test/resources/pom-updater/pom-expected.xml}   |  42 ++--
 .../src/test/resources/pom-updater}/pom.xml        |  42 ++--
 .../src/test/resources/pom-updater/src}/pom.xml    |  42 ++--
 .../camel-karaf/a-pom-expected.xml                 |  81 ++++++++
 .../camel-karaf/c-pom-expected.xml                 |  81 ++++++++
 .../camel-karaf/pom-expected.xml}                  |  26 ++-
 .../single-module-wrapper/camel-karaf}/pom.xml     |  23 ++-
 .../single-module-wrapper/camel/camel-a}/pom.xml   |  47 +++--
 tooling/pom.xml                                    |   7 +-
 100 files changed, 3849 insertions(+), 177 deletions(-)

diff --git a/components/camel-blueprint/pom.xml b/components/camel-blueprint/pom.xml
index 7c5325c3..8f8bb8e8 100644
--- a/components/camel-blueprint/pom.xml
+++ b/components/camel-blueprint/pom.xml
@@ -124,7 +124,6 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-dependency-plugin</artifactId>
-                    <version>3.6.1</version>
                     <configuration>
                         <artifactItems>
                             <artifactItem>
@@ -244,7 +243,6 @@
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-dependency-plugin</artifactId>
-                        <version>3.6.1</version>
                         <executions>
                             <execution>
                                 <id>process-sources</id>
diff --git a/components/pom.xml b/components/pom.xml
index 19b4c8c7..5ebf211b 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -33,9 +33,6 @@
     <name>Apache Camel :: Karaf :: Components</name>
 
     <modules>
-        <module>camel-blueprint</module>
-        <!-- TODO re-add camel-directvm and camel-vm components as they are heavily used in Karaf -->
-        <!-- wrappers -->
         <module>camel-activemq</module>
         <module>camel-amqp</module>
         <module>camel-arangodb</module>
@@ -53,6 +50,7 @@
         <module>camel-bean</module>
         <module>camel-bean-validator</module>
         <module>camel-bindy</module>
+        <module>camel-blueprint</module>
         <module>camel-bonita</module>
         <module>camel-box</module>
         <module>camel-braintree</module>
diff --git a/pom.xml b/pom.xml
index 74c27622..4e251aa7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,6 +71,7 @@
         <!-- <module>bom</module> -->
         <module>tests</module>
         <module>tooling</module>
+        <module>tooling/camel-upgrade</module>
     </modules>
 
     <scm>
@@ -576,9 +577,11 @@
         <spring-amqp-version>3.1.5</spring-amqp-version>
 
         <!-- Plugin versions -->
-        <maven-shade-plugin-version>3.6.0</maven-shade-plugin-version>
         <maven-bundle-plugin-version>5.1.9</maven-bundle-plugin-version>
         <maven-compiler-plugin-version>3.13.0</maven-compiler-plugin-version>
+        <maven-dependency-plugin-version>3.7.0</maven-dependency-plugin-version>
+        <maven-jar-plugin-version>3.4.1</maven-jar-plugin-version>
+        <maven-shade-plugin-version>3.6.0</maven-shade-plugin-version>
     </properties>
 
     <dependencyManagement>
@@ -660,6 +663,16 @@
                         <createDependencyReducedPom>false</createDependencyReducedPom>
                     </configuration>
                 </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <version>${maven-dependency-plugin-version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>${maven-jar-plugin-version}</version>
+                </plugin>
             </plugins>
         </pluginManagement>
         <plugins>
diff --git a/tooling/camel-karaf-feature-maven-plugin/pom.xml b/tooling/camel-karaf-feature-maven-plugin/pom.xml
index 4b81ece5..a79e26a4 100644
--- a/tooling/camel-karaf-feature-maven-plugin/pom.xml
+++ b/tooling/camel-karaf-feature-maven-plugin/pom.xml
@@ -30,7 +30,6 @@
 
     <properties>
         <felix-utils-version>1.11.8</felix-utils-version>
-        <maven-version>3.9.7</maven-version>
     </properties>
     
     <dependencies>
diff --git a/tooling/camel-upgrade/README.md b/tooling/camel-upgrade/README.md
new file mode 100644
index 00000000..ee16d83b
--- /dev/null
+++ b/tooling/camel-upgrade/README.md
@@ -0,0 +1,45 @@
+# Apache Camel Upgrade Tool
+
+### Introduction
+
+The Apache Camel Karaf Upgrade Tool is meant to be used to upgrade the version of Apache Camel in the Apache Camel Karaf
+project. Indeed, several tasks are required to upgrade the version of Apache Camel in the Apache Camel Karaf project, this
+tool simply automates all of them to ease the migration and avoid mistakes.
+
+### Usage
+
+The tool is a simple executable jar that can be run anywhere as long as you have a Java runtime installed.
+    
+```shell
+java -jar target/camel-upgrade-${camel-karaf-version}.jar
+```
+where `${camel-karaf-version}` is the version of the Apache Camel Karaf project.
+
+The tool will ask you several questions to know what you want to do and what are the values you want to use. 
+You can also provide the answers to the questions in a file named `camel-upgrade.properties` in the same directory as
+where the tool is executed.
+
+The file should contain the following keys:
+
+```properties
+# The version of the Apache Camel project to upgrade to
+camel.version = 4.6.0
+# The location of the root folder of the Apache Camel Karaf project to upgrade
+camel.karaf.root = ../../
+# The location of the root folder of the Apache Camel project
+camel.root = ../../../camel
+```
+
+### Features
+
+The tool provides the following features:
+
+* Set the new version of Apache Camel Karaf according to the version of Apache Camel in all the pom files
+* Set the version of Apache Camel in the parent pom file of the project
+* Set the version of third-party libraries in the parent pom file of the project based on the parent pom file of the
+  Apache Camel project
+* Add a new wrapper and feature for all new components
+* Remove the wrapper and feature for all components that have been removed in the new version of Apache Camel
+* Load default input values from the `camel-upgrade.properties` file
+* Automatically checkout the correct tag of the Apache Camel project based if the location of the Apache Camel root folder
+  is not provided
diff --git a/tooling/camel-upgrade/camel-upgrade.properties b/tooling/camel-upgrade/camel-upgrade.properties
new file mode 100644
index 00000000..0f406dd3
--- /dev/null
+++ b/tooling/camel-upgrade/camel-upgrade.properties
@@ -0,0 +1,20 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+camel.version = 4.6.0
+camel.karaf.root = ../../
+camel.root = ../../../camel
diff --git a/tooling/camel-upgrade/pom.xml b/tooling/camel-upgrade/pom.xml
new file mode 100644
index 00000000..d0d1be3d
--- /dev/null
+++ b/tooling/camel-upgrade/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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.karaf</groupId>
+        <artifactId>tooling</artifactId>
+        <version>4.6.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-upgrade</artifactId>
+    <name>Apache Camel :: Karaf :: Tooling :: Camel Upgrade</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jgit</groupId>
+            <artifactId>org.eclipse.jgit</artifactId>
+            <version>${jgit-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>${commons-io-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-model</artifactId>
+            <version>${maven-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j2-impl</artifactId>
+            <version>${log4j2-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>${log4j2-version}</version>
+        </dependency>
+        <!-- tests -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit-jupiter-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>${junit-jupiter-version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/libs</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>libs/</classpathPrefix>
+                            <mainClass>org.apache.camel.karaf.tooling.upgrade.UpgradeCamel</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/ComponentComparator.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/ComponentComparator.java
new file mode 100644
index 00000000..7ba7970d
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/ComponentComparator.java
@@ -0,0 +1,114 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+public abstract class ComponentComparator {
+
+    private final Path camelKarafComponentRoot;
+    private final Path camelComponentRoot;
+
+    protected ComponentComparator(Path camelKarafComponentRoot, Path camelComponentRoot) {
+        this.camelKarafComponentRoot = camelKarafComponentRoot;
+        this.camelComponentRoot = camelComponentRoot;
+    }
+
+    private static boolean isCamelComponentDirectory(File file) {
+        return file.isDirectory() && file.getName().startsWith("camel-");
+    }
+
+    static boolean isCamelSubComponentDirectory(File file) {
+        return isCamelComponentDirectory(file)
+                && !file.getName().endsWith("-codegen")
+                && !file.getName().endsWith("-maven-plugin")
+                && !file.getName().endsWith("-spi")
+                && !file.getName().endsWith("-api");
+    }
+
+    private static List<String> getComponentsInFolder(Path root) throws IOException {
+        File[] files = root.toFile().listFiles(ComponentComparator::isCamelSubComponentDirectory);
+        if (files == null) {
+            throw new IOException("Unable to list the camel sub component in %s".formatted(root));
+        }
+        if (files.length == 0) {
+            return List.of(root.getFileName().toString());
+        } else if (files.length == 1) {
+            return List.of(files[0].getName().replace("-component", ""));
+        } else {
+            return Stream.of(files)
+                    .map(file -> file.getName().replace("-component", ""))
+                    .map(name -> "%s/%s".formatted(root.getFileName(), name))
+                    .toList();
+        }
+    }
+
+    private static Set<String> getComponents(Path root) throws IOException {
+        File[] files = root.toFile().listFiles(ComponentComparator::isCamelComponentDirectory);
+        if (files == null) {
+            throw new IOException("Unable to list the camel component in %s".formatted(root));
+        }
+        List<String> components = new ArrayList<>();
+        for (File file : files) {
+            components.addAll(getComponentsInFolder(file.toPath()));
+        }
+        components.sort(String::compareTo);
+        return new LinkedHashSet<>(components);
+    }
+
+    public void execute() throws IOException {
+        Set<String> componentsInCamelKaraf = getComponents(camelKarafComponentRoot);
+        Set<String> componentsInCamel = getComponents(camelComponentRoot);
+        for (String component : componentsInCamel) {
+            if (componentsInCamelKaraf.contains(component)) {
+                // The component is already in Camel Karaf
+                componentsInCamelKaraf.remove(component);
+            } else {
+                int index = component.indexOf('/');
+                if (index == -1) {
+                    onAddComponent(component);
+                } else {
+                    onAddSubComponent(component.substring(0, index), component.substring(index + 1));
+                }
+            }
+        }
+        for (String component : componentsInCamelKaraf) {
+            int index = component.indexOf('/');
+            if (index == -1) {
+                onRemoveComponent(component);
+            } else {
+                onRemoveSubComponent(component.substring(0, index), component.substring(index + 1));
+            }
+        }
+    }
+
+    protected abstract void onAddSubComponent(String parent, String subComponent) throws IOException;
+
+    protected abstract void onAddComponent(String component) throws IOException;
+
+    protected abstract void onRemoveSubComponent(String parent, String subComponent) throws IOException;
+
+    protected abstract void onRemoveComponent(String component) throws IOException;
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/DefaultValuesProvider.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/DefaultValuesProvider.java
new file mode 100644
index 00000000..62298bc0
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/DefaultValuesProvider.java
@@ -0,0 +1,76 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Optional;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultValuesProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultValuesProvider.class);
+    private static final String CAMEL_ROOT_KEY = "camel.root";
+    private static final String CAMEL_KARAF_ROOT_KEY = "camel.karaf.root";
+    private static final String CAMEL_VERSION_KEY = "camel.version";
+
+    private final Properties defaultValues;
+
+    public DefaultValuesProvider(String path) {
+        this.defaultValues = loadDefaultValues(path);
+    }
+
+    private static Properties loadDefaultValues(String path) {
+        LOG.debug("Loading default values from {}", path);
+        Properties properties = new Properties();
+        File file = new File(path);
+        if (file.exists()) {
+            LOG.debug("Loading default values from {}", file);
+            try (FileReader reader = new FileReader(file)) {
+                properties.load(reader);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
+        return properties;
+    }
+
+    private Optional<String> getDefaultValue(String key) {
+        return Optional.ofNullable(defaultValues.get(key))
+                .map(Object::toString)
+                .map(String::trim)
+                .filter(s -> !s.isEmpty());
+    }
+
+    public Optional<String> getDefaultCamelRoot() {
+        return getDefaultValue(CAMEL_ROOT_KEY);
+    }
+
+    public Optional<String> getDefaultCamelKarafRoot() {
+        return getDefaultValue(CAMEL_KARAF_ROOT_KEY);
+    }
+
+    public Optional<String> getDefaultCamelVersion() {
+        return getDefaultValue(CAMEL_VERSION_KEY);
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/FeatureHandler.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/FeatureHandler.java
new file mode 100644
index 00000000..db547ca2
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/FeatureHandler.java
@@ -0,0 +1,113 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.apache.camel.karaf.tooling.upgrade.Utils.nextLineIndex;
+import static org.apache.camel.karaf.tooling.upgrade.Utils.replaceFileContent;
+
+public class FeatureHandler {
+
+    private static final Pattern FEATURE_IN_FEATURES_XML = Pattern.compile("<feature name=['\"]([^'\"]+)['\"]");
+    private static final String FEATURE_FORMAT = """
+    <feature name='#{camel-component-id}' version='${project.version}' start-level='50'>
+            <feature version='${camel-osgi-version-range}'>camel-core</feature>
+            <bundle>mvn:org.apache.camel.karaf/#{camel-component-id}/${project.version}</bundle>
+        </feature>
+    """;
+
+    private final Path camelKarafFeatures;
+
+    public FeatureHandler(Path camelKarafFeatures) {
+        this.camelKarafFeatures = camelKarafFeatures;
+    }
+
+    public void add(String component) throws IOException {
+        addComponentToFeatures(component);
+    }
+
+    private void addComponentToFeatures(String component) throws IOException {
+        replaceFileContent(camelKarafFeatures, features -> getFeaturesWithComponent(features, component));
+    }
+
+    private static String getFeaturesWithComponent(String features, String component) {
+        int start = features.indexOf("<!-- the following features are sorted A..Z -->");
+        if (start == -1) {
+            throw new IllegalStateException("Unable to find the start position in the features files");
+        }
+        Matcher matcher = FEATURE_IN_FEATURES_XML.matcher(features);
+        StringBuilder result = new StringBuilder();
+        boolean added = false;
+        while (matcher.find(start)) {
+            String feature = matcher.group(1);
+            if (feature.equals(component)) {
+                // Already in the features
+                return features;
+            } else if (feature.compareTo(component) > 0) {
+                result.append(features, 0, matcher.start());
+                result.append(FEATURE_FORMAT.replace("#{camel-component-id}", component));
+                result.append("    ");
+                added = true;
+                start = matcher.start();
+                break;
+            }
+            start = matcher.end();
+        }
+        if (!added) {
+            start = nextLineIndex(features, features.lastIndexOf("</feature>"));
+            result.append(features, 0, start);
+            result.append("    ");
+            result.append(FEATURE_FORMAT.replace("#{camel-component-id}", component));
+        }
+        result.append(features, start, features.length());
+        return result.toString();
+    }
+
+    public void remove(String component) throws IOException {
+        removeComponentFromFeatures(component);
+    }
+
+    private void removeComponentFromFeatures(String component) throws IOException {
+        replaceFileContent(camelKarafFeatures, features -> getFeaturesWithoutComponent(features, component));
+    }
+
+    private static String getFeaturesWithoutComponent(String features, String component) {
+        int index = features.indexOf("<feature name='%s'".formatted(component));
+        if (index == -1) {
+            // Not in the features
+            return features;
+        }
+        int next = features.indexOf("<feature name='camel-", index + 1);
+        StringBuilder result = new StringBuilder();
+        if (next == -1) {
+            String endTag = "</feature>";
+            next = features.lastIndexOf(endTag) + endTag.length();
+            int previous = features.lastIndexOf(endTag, index) + endTag.length();
+            result.append(features, 0, previous);
+            result.append(features, next, features.length());
+        } else {
+            result.append(features, 0, index);
+            result.append(features, next, features.length());
+        }
+        return result.toString();
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/MultiModuleWrapperHandler.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/MultiModuleWrapperHandler.java
new file mode 100644
index 00000000..bf4cf459
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/MultiModuleWrapperHandler.java
@@ -0,0 +1,94 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.apache.camel.karaf.tooling.upgrade.Utils.loadFileFromClassLoader;
+import static org.apache.camel.karaf.tooling.upgrade.Utils.replaceFileContent;
+
+public class MultiModuleWrapperHandler extends WrapperHandler {
+
+    private static final String MULTI_MODULE_POM = loadFileFromClassLoader("/multi-module-pom.xml");
+    private static final String MULTI_MODULE_PARENT_POM = loadFileFromClassLoader("/multi-module-parent-pom.xml");
+
+    public MultiModuleWrapperHandler(Path camelKarafComponentRoot, Path camelComponentRoot, String camelVersion) {
+        super(camelKarafComponentRoot, camelComponentRoot, camelVersion);
+    }
+
+    public void add(String parent, String subComponent) throws IOException {
+        createModuleIfAbsent(parent);
+        createModuleIfAbsent("%s/%s".formatted(parent, subComponent));
+        createMultiModuleParentPomIfAbsent(parent);
+        createMultiModulePom(parent, subComponent);
+        addSubModuleToParentPom(parent, subComponent);
+        addModuleToParentPom(parent);
+    }
+
+    private void createMultiModuleParentPomIfAbsent(String parent) throws IOException {
+        Path path = camelKarafComponentRoot.resolve(parent).resolve("pom.xml");
+        if (Files.exists(path)) {
+            return;
+        }
+        Files.writeString(path, getMultiModuleParentPom(parent));
+    }
+
+    private String getMultiModuleParentPom(String parent) {
+        return MULTI_MODULE_PARENT_POM.replace("#{camel-version}", camelVersion)
+                .replace("#{camel-parent-component-id}", parent)
+                .replace("#{camel-parent-component-name}", getComponentNameFromId(parent));
+    }
+
+    private void addSubModuleToParentPom(String parent, String subComponent) throws IOException {
+        replaceFileContent(camelKarafComponentRoot.resolve(parent).resolve("pom.xml"), pom -> getParentPomWithComponent(pom, subComponent));
+    }
+
+    private void createMultiModulePom(String parent, String subComponent) throws IOException {
+        Files.writeString(camelKarafComponentRoot.resolve(parent).resolve(subComponent).resolve("pom.xml"),
+                getMultiModulePom(parent, subComponent));
+    }
+
+    private String getMultiModulePom(String parent, String subComponent) {
+        return MULTI_MODULE_POM.replace("#{camel-version}", camelVersion)
+                .replace("#{camel-component-id}", subComponent)
+                .replace("#{camel-component-name}", getComponentNameFromId(subComponent))
+                .replace("#{camel-parent-component-id}", parent)
+                .replace("#{camel-parent-component-name}", getComponentNameFromId(parent));
+    }
+
+    public void remove(String parent, String subComponent) throws IOException {
+        removeModuleIfPresent("%s/%s".formatted(parent, subComponent));
+        removeModuleFromParentPom(subComponent, "%s/pom.xml".formatted(parent));
+        removeMultiModuleIfNeeded(parent);
+    }
+
+    private void removeMultiModuleIfNeeded(String parent) throws IOException {
+        Path root = camelKarafComponentRoot.resolve(parent);
+        File[] files = root.toFile().listFiles(ComponentComparator::isCamelSubComponentDirectory);
+        if (files == null) {
+            throw new IOException("Unable to list the camel sub component in %s".formatted(root));
+        }
+        if (files.length == 0) {
+            removeModuleIfPresent(parent);
+            removeModuleFromParentPom(parent, "pom.xml");
+        }
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/ParentPomUpdater.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/ParentPomUpdater.java
new file mode 100644
index 00000000..2ca2839f
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/ParentPomUpdater.java
@@ -0,0 +1,151 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.karaf.tooling.upgrade.Utils.replaceFileContent;
+
+public class ParentPomUpdater {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ParentPomUpdater.class);
+
+    private static final Pattern DEPENDENCY_VERSION_PATTERN = Pattern.compile("<([^>]+)>([^<]+)</([^>]+)>");
+
+    private final String camelVersion;
+    private final Path camelKarafRootPom;
+    private final Path camelParentPom;
+
+    public ParentPomUpdater(Path camelKarafRootPom, Path camelParentPom, String camelVersion) {
+        this.camelVersion = camelVersion;
+        this.camelKarafRootPom = camelKarafRootPom;
+        this.camelParentPom = camelParentPom;
+    }
+
+    public void execute() throws IOException {
+        updateCamelVersion();
+        updateCamelOsgiVersionRange();
+        updateCamelDependenciesVersion();
+    }
+
+    private void updateCamelVersion() throws IOException {
+        LOG.debug("Updating the Camel version to {}", camelVersion);
+        updatePom(Map.of("camel-version", camelVersion));
+    }
+
+    private void updateCamelOsgiVersionRange() throws IOException {
+        String cleanVersion = cleanVersion(camelVersion);
+        String nextVersion = nextVersion(cleanVersion);
+        LOG.debug("Updating the Camel OSGi version to {}", cleanVersion);
+        LOG.debug("Updating the Camel OSGi next version to {}", nextVersion);
+        updatePom(Map.of("camel-osgi-version-clean", cleanVersion, "camel-osgi-next-version-clean", nextVersion));
+    }
+
+    private void updateCamelDependenciesVersion() throws IOException {
+        LOG.debug("Updating the version of the Camel dependencies");
+        setDependenciesVersion(extractDependenciesVersion(camelParentPom));
+    }
+
+    private void updatePom(Map<String, String> changes) throws IOException {
+        replaceFileContent(camelKarafRootPom,
+                pom -> {
+                    for (Map.Entry<String, String> entry : changes.entrySet()) {
+                        pom = pom.replaceFirst("<%s>(.*)</%s>".formatted(entry.getKey(), entry.getKey()),
+                                "<%s>%s</%s>".formatted(entry.getKey(), entry.getValue(), entry.getKey()));
+                    }
+                    return pom;
+                }
+        );
+    }
+
+    private void setDependenciesVersion(String dependencies) throws IOException {
+        replaceFileContent(camelKarafRootPom, pom -> getPomWithDependenciesVersion(pom, dependencies));
+    }
+
+    private static String getPomWithDependenciesVersion(String pom, String dependencies) {
+        String startPattern = "<!-- START: Maven Properties defining the version of 3rd party libraries used in Camel -->";
+        int start = pom.indexOf(startPattern);
+        if (start == -1) {
+            throw new IllegalStateException("Unable to find the start position in parent pom file of Camel Karaf");
+        }
+        int end = pom.indexOf("<!-- END: Maven Properties defining the version of 3rd party libraries used in Camel -->", start);
+        if (end == -1) {
+            throw new IllegalStateException("Unable to find the end position in parent pom file of Camel");
+        }
+        StringBuilder result = new StringBuilder();
+        result.append(pom, 0, start);
+        result.append(startPattern);
+        result.append('\n');
+        result.append(dependencies);
+        result.append("        ");
+        result.append(pom, end, pom.length());
+        return result.toString();
+    }
+
+    private static String extractDependenciesVersion(Path path) throws IOException {
+        String pom = Files.readString(path, StandardCharsets.UTF_8);
+        String startPattern = "<!-- dependency versions -->";
+        int start = pom.indexOf(startPattern);
+        if (start == -1) {
+            throw new IllegalStateException("Unable to find the start position in parent pom file of Camel");
+        }
+        int end = pom.indexOf("</properties>", start);
+        if (end == -1) {
+            throw new IllegalStateException("Unable to find the end position in parent pom file of Camel");
+        }
+        return extractVersionsOnly(pom.substring(start + startPattern.length(), end));
+    }
+
+    private static String extractVersionsOnly(String content) {
+        StringBuilder result = new StringBuilder();
+        var matcher = DEPENDENCY_VERSION_PATTERN.matcher(content);
+        int start = 0;
+        while (matcher.find(start)) {
+            String tagName = matcher.group(1);
+            if (acceptTag(tagName)) {
+                tagName = tagName.replace('.', '-');
+                result.append("        <%s>%s</%s>%n".formatted(tagName, matcher.group(2), tagName));
+            }
+            start = matcher.end();
+        }
+        return result.toString();
+    }
+
+    private static boolean acceptTag(String tagName) {
+        return !tagName.startsWith("maven");
+    }
+
+    private static String nextVersion(String version) {
+        String[] parts = version.split("\\.");
+        int last = Integer.parseInt(parts[parts.length - 1]);
+        parts[parts.length - 1] = String.valueOf(last + 1);
+        return String.join(".", parts);
+    }
+
+    private static String cleanVersion(String version) {
+        return version.substring(0, version.lastIndexOf('.'));
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/PomUpdater.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/PomUpdater.java
new file mode 100644
index 00000000..2df6da82
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/PomUpdater.java
@@ -0,0 +1,74 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static org.apache.camel.karaf.tooling.upgrade.Utils.replaceFileContent;
+
+public class PomUpdater extends SimpleFileVisitor<Path> {
+
+    private static final Set<String> EXCLUDED_DIRECTORIES = Set.of("target", ".git", "src", ".mvn");
+    private static final Pattern VERSION_TAG_PATTERN = Pattern.compile("<version>[^<]+-SNAPSHOT</version>");
+    private final String camelVersion;
+    private final Path camelKarafRootPom;
+
+    public PomUpdater(Path camelKarafRootPom, String camelVersion) {
+        this.camelVersion = camelVersion;
+        this.camelKarafRootPom = camelKarafRootPom;
+    }
+
+    public void execute() throws IOException {
+        Files.walkFileTree(camelKarafRootPom, this);
+    }
+
+    @Override
+    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+        if (acceptDirectory(dir)) {
+            return FileVisitResult.CONTINUE;
+        }
+        return FileVisitResult.SKIP_SUBTREE;
+    }
+
+    private boolean acceptDirectory(Path dir) {
+        return !EXCLUDED_DIRECTORIES.contains(dir.getFileName().toString());
+    }
+
+    @Override
+    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+        if (isPomFile(file)) {
+            updatePom(file);
+        }
+        return FileVisitResult.CONTINUE;
+    }
+
+    private void updatePom(Path file) throws IOException {
+        replaceFileContent(file, content -> VERSION_TAG_PATTERN.matcher(content).replaceAll("<version>%s-SNAPSHOT</version>".formatted(camelVersion)));
+    }
+
+    private boolean isPomFile(Path file) {
+        return file.getFileName().toString().equals("pom.xml");
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/SingleModuleWrapperHandler.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/SingleModuleWrapperHandler.java
new file mode 100644
index 00000000..220042ff
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/SingleModuleWrapperHandler.java
@@ -0,0 +1,87 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import static org.apache.camel.karaf.tooling.upgrade.Utils.loadFileFromClassLoader;
+
+public class SingleModuleWrapperHandler extends WrapperHandler {
+
+    private static final String SINGLE_MODULE_POM = loadFileFromClassLoader("/single-module-pom.xml");
+
+    public SingleModuleWrapperHandler(Path camelKarafComponentRoot, Path camelComponentRoot, String camelVersion) {
+        super(camelKarafComponentRoot, camelComponentRoot, camelVersion);
+    }
+
+    public void add(String component) throws IOException {
+        createModuleIfAbsent(component);
+        createSingleModulePom(component);
+        addModuleToParentPom(component);
+    }
+
+    private void createSingleModulePom(String component) throws IOException {
+        Files.writeString(camelKarafComponentRoot.resolve(component).resolve("pom.xml"),
+                getSingleModulePom(component));
+    }
+
+    private String getSingleModulePom(String component) throws IOException {
+        return SINGLE_MODULE_POM.replace("#{camel-version}", camelVersion)
+                .replace("#{camel-component-id}", component)
+                .replace("#{camel-component-name}", getComponentName(component));
+    }
+
+    private String getComponentName(String component) throws IOException {
+        Path pom = camelComponentRoot.resolve(component).resolve("pom.xml");
+        String result = null;
+        if (Files.exists(pom)) {
+            result = getComponentNameFomPom(pom);
+        }
+        if (result == null) {
+            result = getComponentNameFromId(component);
+        }
+        return result;
+    }
+
+    private static String getComponentNameFomPom(Path pom) throws IOException {
+        try {
+            MavenXpp3Reader reader = new MavenXpp3Reader();
+            Model model = reader.read(new FileReader(pom.toFile()));
+            String name = model.getName();
+            int index = name.lastIndexOf("::");
+            if (index == -1) {
+                return null;
+            }
+            return name.substring(index + 2).trim();
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void remove(String component) throws IOException {
+        removeModuleIfPresent(component);
+        removeModuleFromParentPom(component, "pom.xml");
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/UpgradeCamel.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/UpgradeCamel.java
new file mode 100644
index 00000000..94a46485
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/UpgradeCamel.java
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.karaf.tooling.upgrade;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.commons.io.FileUtils;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UpgradeCamel {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UpgradeCamel.class);
+
+    private static final String COMPONENTS_FOLDER = "components";
+
+    public static void main(String[] args) throws Exception {
+        LOG.info("Apache Camel Upgrade Tool");
+        UserInputProvider userInputProvider = new UserInputProvider(System.console(), new DefaultValuesProvider("camel-upgrade.properties"));
+        upgrade(
+            userInputProvider.readCamelVersion(), userInputProvider.readCamelKarafRootDirectory(),
+            userInputProvider.readCamelRootDirectory(), userInputProvider::doAction
+        );
+    }
+
+    private static void upgrade(String camelVersion, Path camelKarafRoot, Path camelRoot, Function<String, Boolean> askForAction) throws GitAPIException, IOException {
+        try (UpgradeCamelContext context = new UpgradeCamelContext(camelVersion, camelKarafRoot, camelRoot, askForAction)) {
+            updateAllPoms(context);
+            checkoutCamelIfNeeded(context);
+            updateParentPom(context);
+            compareComponents(context);
+        }
+    }
+
+    private static void updateAllPoms(UpgradeCamelContext context) throws IOException {
+        new PomUpdater(context.camelKarafRoot(), context.camelVersion()).execute();
+    }
+
+    private static void updateParentPom(UpgradeCamelContext context) throws IOException {
+        new ParentPomUpdater(context.camelKarafRoot().resolve("pom.xml"),
+                context.camelRoot().resolve("parent/pom.xml"),
+                context.camelVersion())
+                .execute();
+    }
+
+    private static void compareComponents(UpgradeCamelContext context) throws IOException {
+        new UpgradeCamelComponentComparator(context).execute();
+    }
+
+    private static void checkoutCamelIfNeeded(UpgradeCamelContext context) throws GitAPIException {
+        if (context.cloned()) {
+            checkoutCamel(context);
+        }
+    }
+
+    private static void checkoutCamel(UpgradeCamelContext context) throws GitAPIException {
+        LOG.info("Cloning the Camel repository into {}", context.camelRoot().toAbsolutePath());
+        String tag = "refs/tags/camel-%s".formatted(context.camelVersion());
+        try (Git git = Git.cloneRepository()
+                .setURI("https://github.com/apache/camel.git")
+                .setDirectory(context.camelRoot().toFile())
+                .setBranchesToClone(List.of(tag))
+                .setBranch(tag)
+                .call()) {
+            LOG.info("Camel repository successfully cloned");
+        }
+    }
+
+    private static class UpgradeCamelComponentComparator extends ComponentComparator {
+        private final UpgradeCamelContext context;
+
+        UpgradeCamelComponentComparator(UpgradeCamelContext context) {
+            super(context.camelKarafRoot().resolve(COMPONENTS_FOLDER), context.camelRoot().resolve(COMPONENTS_FOLDER));
+            this.context = context;
+        }
+
+        @Override
+        protected void onAddSubComponent(String parent, String subComponent) throws IOException {
+            if (context.doAction("The sub component %s is not in Camel Karaf. Do you want to add it?".formatted(subComponent))) {
+                addSubComponent(parent, subComponent);
+            }
+        }
+
+        private void addSubComponent(String parent, String subComponent) throws IOException {
+            LOG.info("Adding sub component {}", subComponent);
+            context.multiModuleWrapperHandler().add(parent, subComponent);
+            context.featureHandler().add(subComponent);
+        }
+
+        @Override
+        protected void onAddComponent(String component) throws IOException {
+            if (context.doAction("The component %s is not in Camel Karaf. Do you want to add it?".formatted(component))) {
+                addComponent(component);
+            }
+        }
+
+        private void addComponent(String component) throws IOException {
+            LOG.info("Adding component {}", component);
+            context.singleModuleWrapperHandler().add(component);
+            context.featureHandler().add(component);
+        }
+
+        @Override
+        protected void onRemoveSubComponent(String parent, String subComponent) throws IOException {
+            if (context.doAction("The sub component %s is not in Camel. Do you want to remove it?".formatted(subComponent))) {
+                removeSubComponent(parent, subComponent);
+            }
+        }
+
+        private void removeSubComponent(String parent, String subComponent) throws IOException {
+            LOG.info("Removing sub component {}", subComponent);
+            context.multiModuleWrapperHandler().remove(parent, subComponent);
+            context.featureHandler().remove(subComponent);
+        }
+
+        @Override
+        protected void onRemoveComponent(String component) throws IOException {
+            if (context.doAction("The component %s is not in Camel. Do you want to remove it?".formatted(component))) {
+                removeComponent(component);
+            }
+        }
+
+        private void removeComponent(String component) throws IOException {
+            LOG.info("Removing component {}", component);
+            context.singleModuleWrapperHandler().remove(component);
+            context.featureHandler().remove(component);
+        }
+    }
+
+    private static class UpgradeCamelContext implements Closeable {
+        private final String camelVersion;
+        private final Path camelKarafRoot;
+        private final Path camelRoot;
+        private final boolean cloned;
+        private final Function<String, Boolean> askForAction;
+        private final MultiModuleWrapperHandler multiModuleWrapperHandler;
+        private final SingleModuleWrapperHandler singleModuleWrapperHandler;
+        private final FeatureHandler featureHandler;
+
+        private UpgradeCamelContext(String camelVersion, Path camelKarafRoot, Path camelRoot,
+                                    Function<String, Boolean> askForAction) throws IOException {
+            this.camelVersion = camelVersion;
+            this.camelKarafRoot = camelKarafRoot;
+            if (camelRoot == null) {
+                this.camelRoot = Files.createTempDirectory("camel-upgrade");
+                this.cloned = true;
+            } else {
+                this.camelRoot = camelRoot;
+                this.cloned = false;
+            }
+            this.askForAction = askForAction;
+            Path camelKarafComponentRoot = camelKarafRoot.resolve(COMPONENTS_FOLDER);
+            Path camelComponentRoot = camelRoot.resolve(COMPONENTS_FOLDER);
+            this.multiModuleWrapperHandler = new MultiModuleWrapperHandler(camelKarafComponentRoot, camelComponentRoot,
+                    camelVersion);
+            this.singleModuleWrapperHandler = new SingleModuleWrapperHandler(camelKarafComponentRoot, camelComponentRoot,
+                    camelVersion);
+            this.featureHandler = new FeatureHandler(camelKarafRoot.resolve("features/src/main/feature/camel-features.xml"));
+        }
+
+        String camelVersion() {
+            return camelVersion;
+        }
+
+        Path camelKarafRoot() {
+            return camelKarafRoot;
+        }
+
+        Path camelRoot() {
+            return camelRoot;
+        }
+
+        boolean cloned() {
+            return cloned;
+        }
+
+        boolean doAction(String messageFormat) {
+            return askForAction.apply(messageFormat);
+        }
+
+        MultiModuleWrapperHandler multiModuleWrapperHandler() {
+            return multiModuleWrapperHandler;
+        }
+
+        SingleModuleWrapperHandler singleModuleWrapperHandler() {
+            return singleModuleWrapperHandler;
+        }
+
+        FeatureHandler featureHandler() {
+            return featureHandler;
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (cloned) {
+                FileUtils.deleteDirectory(camelRoot.toFile());
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/UserInputProvider.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/UserInputProvider.java
new file mode 100644
index 00000000..99d5002a
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/UserInputProvider.java
@@ -0,0 +1,117 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.Console;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UserInputProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserInputProvider.class);
+
+    private final Console console;
+    private final DefaultValuesProvider defaultValuesProvider;
+
+    public UserInputProvider(Console console, DefaultValuesProvider defaultValuesProvider) {
+        this.console = Objects.requireNonNull(console, "Console is required");
+        this.defaultValuesProvider = Objects.requireNonNull(defaultValuesProvider, "DefaultValuesProvider is required");
+    }
+
+    public Path readCamelRootDirectory() {
+        return checkCamelRoot(
+            readLine("Camel oot Directory%s (cloned if not set): ", "Camel Root Directory",
+                    defaultValuesProvider.getDefaultCamelRoot(), false)
+        );
+    }
+
+    public Path readCamelKarafRootDirectory() {
+        return checkCamelKarafRoot(
+            readLine("Camel Karaf Root Directory%s: ", "Camel Karaf Root Directory",
+                    defaultValuesProvider.getDefaultCamelKarafRoot(), true)
+        );
+    }
+
+    public String readCamelVersion() {
+        return readLine("Expected Camel Version%s: ", "Camel Version", defaultValuesProvider.getDefaultCamelVersion(), true);
+    }
+
+    public boolean doAction(String message) {
+        String answer = console.readLine("%s (y/n): ".formatted(message));
+        return "y".equalsIgnoreCase(answer);
+    }
+
+    private String readLine(String messageFormat, String name, Optional<String> defaultValue, boolean required) {
+        String value = console.readLine(messageFormat.formatted(defaultValue.map(" [%s]"::formatted).orElse("")));
+        if (value == null || value.isBlank()) {
+            value = defaultValue.orElse(null);
+            if (value == null) {
+                if (required) {
+                    LOG.error("{} is required.", name);
+                    System.exit(1);
+                }
+            } else {
+                LOG.info("Using default {} {}", name, value);
+            }
+        }
+        return value;
+    }
+
+    private static Path checkCamelRoot(String camelRootDirectory) {
+        if (camelRootDirectory == null || camelRootDirectory.isBlank()) {
+            return null;
+        }
+        Path camelRoot = Paths.get(camelRootDirectory);
+        if (!Files.exists(camelRoot)) {
+            LOG.error("Camel root directory does not exist.");
+            System.exit(1);
+        } else if (!Files.exists(camelRoot.resolve("pom.xml"))) {
+            LOG.error("Camel root directory does not contain any pom file.");
+            System.exit(1);
+        } else if (!Files.exists(camelRoot.resolve("components/pom.xml"))) {
+            LOG.error("Camel root directory does not contain any sub module components.");
+            System.exit(1);
+        }
+        return camelRoot;
+    }
+
+    private static Path checkCamelKarafRoot(String camelKarafRootDirectory) {
+        if (camelKarafRootDirectory == null || camelKarafRootDirectory.isBlank()) {
+            LOG.error("Camel Karaf root directory is required.");
+            System.exit(1);
+        }
+        Path camelKarafRoot = Paths.get(camelKarafRootDirectory);
+        if (!Files.exists(camelKarafRoot)) {
+            LOG.error("Camel Karaf root directory does not exist.");
+            System.exit(1);
+        } else if (!Files.exists(camelKarafRoot.resolve("pom.xml"))) {
+            LOG.error("Camel Karaf root directory does not contain any pom file.");
+            System.exit(1);
+        } else if (!Files.exists(camelKarafRoot.resolve("components/pom.xml"))) {
+            LOG.error("Camel Karaf root directory does not contain any sub module components.");
+            System.exit(1);
+        }
+        return camelKarafRoot;
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/Utils.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/Utils.java
new file mode 100644
index 00000000..8956359c
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/Utils.java
@@ -0,0 +1,57 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.function.UnaryOperator;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class Utils {
+
+    private static final Pattern LINE_SEPARATOR_PATTERN = Pattern.compile("\r\n|[\n\r\u2028\u2029\u0085]");
+    private Utils() {}
+
+    static String loadFileFromClassLoader(String path) {
+        try (InputStream resource = UpgradeCamel.class.getResourceAsStream(path)) {
+            if (resource == null) {
+                throw new IOException("Resource %s not found".formatted(path));
+            }
+            return new String(resource.readAllBytes(), StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    static void replaceFileContent(Path path, UnaryOperator<String> contentUpdater) throws IOException {
+        Files.writeString(path, contentUpdater.apply(Files.readString(path, StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+    }
+
+    static int nextLineIndex(String content, int start) {
+        Matcher matcher = LINE_SEPARATOR_PATTERN.matcher(content);
+        if (matcher.find(start)) {
+            return matcher.end();
+        }
+        return -1;
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/WrapperHandler.java b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/WrapperHandler.java
new file mode 100644
index 00000000..3ad37822
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/java/org/apache/camel/karaf/tooling/upgrade/WrapperHandler.java
@@ -0,0 +1,136 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FileUtils;
+
+import static org.apache.camel.karaf.tooling.upgrade.Utils.replaceFileContent;
+
+public abstract class WrapperHandler {
+
+    private static final Pattern MODULE_IN_PARENT_POM = Pattern.compile("<module>(.*)</module>");
+
+    protected final Path camelKarafComponentRoot;
+    protected final Path camelComponentRoot;
+    protected final String camelVersion;
+
+    protected WrapperHandler(Path camelKarafComponentRoot, Path camelComponentRoot, String camelVersion) {
+        this.camelKarafComponentRoot = camelKarafComponentRoot;
+        this.camelComponentRoot = camelComponentRoot;
+        this.camelVersion = camelVersion;
+    }
+
+    protected void createModuleIfAbsent(String module) throws IOException {
+        Path path = camelKarafComponentRoot.resolve(module);
+        if (Files.exists(path)) {
+            return;
+        }
+        Files.createDirectory(path);
+    }
+
+    protected void removeModuleIfPresent(String module) throws IOException {
+        Path path = camelKarafComponentRoot.resolve(module);
+        if (Files.exists(path)) {
+            FileUtils.deleteDirectory(path.toFile());
+        }
+    }
+
+    protected void removeModuleFromParentPom(String component, String path) throws IOException {
+        replaceFileContent(camelKarafComponentRoot.resolve(path), pom -> getParentPomWithoutComponent(pom, component));
+    }
+
+    protected static String getParentPomWithoutComponent(String pom, String component) {
+        String pattern = "<module>%s</module>".formatted(component);
+        int index = pom.indexOf(pattern);
+        if (index == -1) {
+            // Not in the parent pom
+            return pom;
+        }
+        int next = pom.indexOf("<module>", index + 1);
+        StringBuilder result = new StringBuilder();
+        if (next == -1) {
+            next = index + pattern.length();
+            String endTag = "</module>";
+            int previous = pom.lastIndexOf(endTag, index) + endTag.length();
+            result.append(pom, 0, previous);
+            result.append(pom, next, pom.length());
+        } else {
+            result.append(pom, 0, index);
+            result.append(pom, next, pom.length());
+        }
+        return result.toString();
+    }
+
+    protected void addModuleToParentPom(String component) throws IOException {
+        replaceFileContent(camelKarafComponentRoot.resolve("pom.xml"), pom -> getParentPomWithComponent(pom, component));
+    }
+
+    protected static String getParentPomWithComponent(String pom, String component) {
+        Matcher matcher = MODULE_IN_PARENT_POM.matcher(pom);
+        StringBuilder result = new StringBuilder();
+        int start = 0;
+        boolean added = false;
+        while (matcher.find(start)) {
+            String module = matcher.group(1);
+            if (module.equals(component)) {
+                // Already in the parent pom
+                return pom;
+            } else if (module.equals("NA")) {
+                result.append(pom, 0, matcher.start());
+                result.append("<module>%s</module>".formatted(component));
+                added = true;
+                start = matcher.end();
+                break;
+            } else if (module.compareTo(component) > 0) {
+                result.append(pom, 0, matcher.start());
+                result.append("<module>%s</module>%n        ".formatted(component));
+                added = true;
+                start = matcher.start();
+                break;
+            }
+            start = matcher.end();
+        }
+        if (!added) {
+            result.append(pom, 0, start);
+            result.append("%n        <module>%s</module>".formatted(component));
+        }
+        result.append(pom, start, pom.length());
+        return result.toString();
+    }
+
+    protected static String getComponentNameFromId(String componentId) {
+        StringBuilder result = new StringBuilder();
+        boolean first = true;
+        for (String part : componentId.substring("camel-".length()).split("-")) {
+            if (first) {
+                first = false;
+            } else {
+                result.append(' ');
+            }
+            result.append(part.substring(0, 1).toUpperCase()).append(part.substring(1));
+        }
+        return result.toString();
+    }
+}
diff --git a/tooling/camel-upgrade/src/main/resources/log4j2.properties b/tooling/camel-upgrade/src/main/resources/log4j2.properties
new file mode 100644
index 00000000..2662e109
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/resources/log4j2.properties
@@ -0,0 +1,21 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.stdout.type = Console
+appender.stdout.name = stdout
+rootLogger.level = INFO
+rootLogger.appenderRef.out.ref = stdout
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/main/resources/multi-module-parent-pom.xml
similarity index 74%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/main/resources/multi-module-parent-pom.xml
index 6cc35313..a5f8f262 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/main/resources/multi-module-parent-pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -16,21 +18,21 @@
 
 -->
 <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
-    
+
     <parent>
         <groupId>org.apache.camel.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <artifactId>camel-karaf-components</artifactId>
+        <version>#{camel-version}-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    
-    <artifactId>tooling</artifactId>
+
+    <artifactId>#{camel-parent-component-id}-parent</artifactId>
     <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
+    <name>Apache Camel :: Karaf :: Components :: #{camel-parent-component-name} :: Parent</name>
+
     <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>NA</module>
     </modules>
-    
-</project>
\ No newline at end of file
+</project>
diff --git a/tooling/camel-upgrade/src/main/resources/multi-module-pom.xml b/tooling/camel-upgrade/src/main/resources/multi-module-pom.xml
new file mode 100644
index 00000000..6736ab71
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/resources/multi-module-pom.xml
@@ -0,0 +1,81 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.karaf</groupId>
+        <artifactId>#{camel-parent-component-id}-parent</artifactId>
+        <version>#{camel-version}-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>#{camel-component-id}</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Camel :: Karaf :: Components :: #{camel-parent-component-name} :: #{camel-component-name}</name>
+
+    <properties>
+        <camel.osgi.export>
+            org.apache.camel*;version=${camel-version}
+        </camel.osgi.export>
+        <camel.osgi.import>
+            *
+        </camel.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>#{camel-component-id}</artifactId>
+            <version>${camel-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.camel:#{camel-component-id}</include>
+                                </includes>
+                            </artifactSet>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/tooling/camel-upgrade/src/main/resources/single-module-pom.xml b/tooling/camel-upgrade/src/main/resources/single-module-pom.xml
new file mode 100644
index 00000000..4e8e66cc
--- /dev/null
+++ b/tooling/camel-upgrade/src/main/resources/single-module-pom.xml
@@ -0,0 +1,81 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.karaf</groupId>
+        <artifactId>camel-karaf-components</artifactId>
+        <version>#{camel-version}-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>#{camel-component-id}</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Camel :: Karaf :: Components :: #{camel-component-name}</name>
+
+    <properties>
+        <camel.osgi.export>
+            org.apache.camel*;version=${camel-version}
+        </camel.osgi.export>
+        <camel.osgi.import>
+            *
+        </camel.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>#{camel-component-id}</artifactId>
+            <version>${camel-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.camel:#{camel-component-id}</include>
+                                </includes>
+                            </artifactSet>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/ComponentComparatorTest.java b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/ComponentComparatorTest.java
new file mode 100644
index 00000000..e691f6c2
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/ComponentComparatorTest.java
@@ -0,0 +1,108 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit test for {@link ComponentComparator}.
+ */
+class ComponentComparatorTest {
+
+    @Test
+    void testAll() throws IOException {
+        InnerComponentComparator comparator = new InnerComponentComparator();
+        comparator.execute();
+        assertFalse(comparator.hasAddedComponent("camel-both-single"));
+        assertFalse(comparator.hasRemovedComponent("camel-both-single"));
+        assertFalse(comparator.hasAddedComponent("camel-both-multiple"));
+        assertFalse(comparator.hasRemovedComponent("camel-both-multiple"));
+        assertTrue(comparator.hasAddedComponentWithoutSubComponents("camel-only"));
+        assertTrue(comparator.hasRemovedComponentWithoutSubComponents("camel-karaf-only"));
+        assertTrue(comparator.hasAddedSubComponent("camel-multiple", "camel-multiple-only"));
+        assertTrue(comparator.hasRemovedSubComponent("camel-karaf-multiple", "camel-karaf-multiple-only"));
+        assertTrue(comparator.hasAddedComponentWithoutSubComponents("camel-complex-single"));
+        assertTrue(comparator.hasAddedSubComponent("camel-complex-multiple", "camel-complex-multiple-a"));
+        assertTrue(comparator.hasAddedSubComponent("camel-complex-multiple", "camel-complex-multiple-b"));
+        assertTrue(comparator.hasAddedSubComponent("camel-complex-multiple", "camel-complex-multiple"));
+    }
+
+    private static class InnerComponentComparator extends ComponentComparator {
+
+        private final Map<String, Set<String>> addedComponents = new HashMap<>();
+        private final Map<String, Set<String>> removedComponents = new HashMap<>();
+
+        InnerComponentComparator() {
+            super(Paths.get("src/test/resources/comparator/camel-karaf"), Paths.get("src/test/resources/comparator/camel"));
+        }
+
+        @Override
+        protected void onAddSubComponent(String parent, String subComponent) {
+            addedComponents.computeIfAbsent(parent, k -> new HashSet<>()).add(subComponent);
+        }
+
+        @Override
+        protected void onAddComponent(String component) {
+            addedComponents.put(component, Set.of());
+        }
+
+        @Override
+        protected void onRemoveSubComponent(String parent, String subComponent) {
+            removedComponents.computeIfAbsent(parent, k -> new HashSet<>()).add(subComponent);
+        }
+
+        @Override
+        protected void onRemoveComponent(String component) {
+            removedComponents.put(component, Set.of());
+        }
+
+        boolean hasAddedComponent(String component) {
+            return addedComponents.containsKey(component);
+        }
+
+        boolean hasRemovedComponent(String component) {
+            return removedComponents.containsKey(component);
+        }
+
+        boolean hasAddedComponentWithoutSubComponents(String component) {
+            return hasAddedComponent(component) && addedComponents.get(component).isEmpty();
+        }
+
+        boolean hasRemovedComponentWithoutSubComponents(String component) {
+            return hasRemovedComponent(component) && removedComponents.get(component).isEmpty();
+        }
+
+        boolean hasAddedSubComponent(String parent, String subComponent) {
+            return addedComponents.getOrDefault(parent, Set.of()).contains(subComponent);
+        }
+
+        boolean hasRemovedSubComponent(String parent, String subComponent) {
+            return removedComponents.getOrDefault(parent, Set.of()).contains(subComponent);
+        }
+    }
+}
diff --git a/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/DefaultValuesProviderTest.java b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/DefaultValuesProviderTest.java
new file mode 100644
index 00000000..f7ceccd6
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/DefaultValuesProviderTest.java
@@ -0,0 +1,60 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit test for {@link DefaultValuesProvider}.
+ */
+class DefaultValuesProviderTest {
+
+    @DisplayName("Should not fail when the file is absent")
+    @Test
+    void fileAbsent() {
+        DefaultValuesProvider provider = new DefaultValuesProvider("nonexistent");
+        assertTrue(provider.getDefaultCamelVersion().isEmpty());
+        assertTrue(provider.getDefaultCamelKarafRoot().isEmpty());
+        assertTrue(provider.getDefaultCamelRoot().isEmpty());
+    }
+
+    @DisplayName("Should not fail when the file is empty")
+    @Test
+    void fileEmpty() {
+        DefaultValuesProvider provider = new DefaultValuesProvider("src/test/resources/default-values/empty.properties");
+        assertTrue(provider.getDefaultCamelVersion().isEmpty());
+        assertTrue(provider.getDefaultCamelKarafRoot().isEmpty());
+        assertTrue(provider.getDefaultCamelRoot().isEmpty());
+    }
+
+    @DisplayName("Should find values when available")
+    @Test
+    void fileFull() {
+        DefaultValuesProvider provider = new DefaultValuesProvider("src/test/resources/default-values/full.properties");
+        assertTrue(provider.getDefaultCamelVersion().isPresent());
+        assertEquals("4.0.0", provider.getDefaultCamelVersion().get());
+        assertTrue(provider.getDefaultCamelKarafRoot().isPresent());
+        assertEquals("camel-karaf-root", provider.getDefaultCamelKarafRoot().get());
+        assertTrue(provider.getDefaultCamelRoot().isPresent());
+        assertEquals("camel-root", provider.getDefaultCamelRoot().get());
+    }
+}
diff --git a/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/FeatureHandlerTest.java b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/FeatureHandlerTest.java
new file mode 100644
index 00000000..665ddd1a
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/FeatureHandlerTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Unit test for {@link FeatureHandler}.
+ */
+class FeatureHandlerTest {
+
+    @DisplayName("Should fail when the file doesn't contain the starting pattern")
+    @Test
+    void fileEmpty() {
+        FeatureHandler handler = new FeatureHandler(Paths.get("target/test-classes/features/empty.xml"));
+        assertThrows(IllegalStateException.class, () -> handler.add("camel-foo"));
+    }
+
+    @DisplayName("Should be able to inject a feature in first position")
+    @Test
+    void injectBefore() throws Exception {
+        FeatureHandler handler = new FeatureHandler(Paths.get("target/test-classes/features/inject-before.xml"));
+        handler.add("camel-a");
+        assertEquals(
+            Files.readString(Paths.get("target/test-classes/features/inject-before-expected.xml")),
+            Files.readString(Paths.get("target/test-classes/features/inject-before.xml")));
+    }
+
+    @DisplayName("Should be able to inject a feature between existing features")
+    @Test
+    void injectMiddle() throws Exception {
+        FeatureHandler handler = new FeatureHandler(Paths.get("target/test-classes/features/inject-middle.xml"));
+        handler.add("camel-c");
+        assertEquals(
+            Files.readString(Paths.get("target/test-classes/features/inject-middle-expected.xml")),
+            Files.readString(Paths.get("target/test-classes/features/inject-middle.xml")));
+    }
+
+    @DisplayName("Should be able to inject a feature in last position")
+    @Test
+    void injectAfter() throws Exception {
+        FeatureHandler handler = new FeatureHandler(Paths.get("target/test-classes/features/inject-after.xml"));
+        handler.add("camel-e");
+        assertEquals(
+            Files.readString(Paths.get("target/test-classes/features/inject-after-expected.xml")),
+            Files.readString(Paths.get("target/test-classes/features/inject-after.xml")));
+    }
+
+    @DisplayName("Should be able to remove a feature in first position")
+    @Test
+    void removeBefore() throws Exception {
+        FeatureHandler handler = new FeatureHandler(Paths.get("target/test-classes/features/remove-before.xml"));
+        handler.remove("camel-a");
+        assertEquals(
+            Files.readString(Paths.get("target/test-classes/features/remove-before-expected.xml")),
+            Files.readString(Paths.get("target/test-classes/features/remove-before.xml")));
+    }
+
+    @DisplayName("Should be able to remove a feature between existing features")
+    @Test
+    void removeMiddle() throws Exception {
+        FeatureHandler handler = new FeatureHandler(Paths.get("target/test-classes/features/remove-middle.xml"));
+        handler.remove("camel-b");
+        assertEquals(
+            Files.readString(Paths.get("target/test-classes/features/remove-middle-expected.xml")),
+            Files.readString(Paths.get("target/test-classes/features/remove-middle.xml")));
+    }
+
+    @DisplayName("Should be able to remove a feature in last position")
+    @Test
+    void removeAfter() throws Exception {
+        FeatureHandler handler = new FeatureHandler(Paths.get("target/test-classes/features/remove-after.xml"));
+        handler.remove("camel-c");
+        assertEquals(
+            Files.readString(Paths.get("target/test-classes/features/remove-after-expected.xml")),
+            Files.readString(Paths.get("target/test-classes/features/remove-after.xml")));
+    }
+}
diff --git a/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/MultiModuleWrapperHandlerTest.java b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/MultiModuleWrapperHandlerTest.java
new file mode 100644
index 00000000..c687145f
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/MultiModuleWrapperHandlerTest.java
@@ -0,0 +1,74 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit test for {@link MultiModuleWrapperHandler}.
+ */
+class MultiModuleWrapperHandlerTest {
+
+    @Test
+    void testAll() throws Exception {
+        Path camelKarafComponentRoot = Paths.get("target/test-classes/multi-module-wrapper/camel-karaf");
+        MultiModuleWrapperHandler handler = new MultiModuleWrapperHandler(
+                camelKarafComponentRoot,
+                Paths.get("target/test-classes/multi-module-wrapper/camel"),
+                "4.0.0");
+        handler.add("camel-b", "camel-b2");
+        Path pathRootPom = Paths.get("target/test-classes/multi-module-wrapper/camel-karaf/pom.xml");
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/multi-module-wrapper/camel-karaf/expected-pom.xml")),
+                Files.readString(pathRootPom));
+        handler.add("camel-b", "camel-b1");
+        handler.add("camel-b", "camel-b3");
+        Path pathPomB = camelKarafComponentRoot.resolve("camel-b/pom.xml");
+        assertTrue(Files.exists(pathPomB));
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/multi-module-wrapper/camel-karaf/b-pom-expected.xml")),
+                Files.readString(pathPomB));
+        Path pathPom = camelKarafComponentRoot.resolve("camel-b/camel-b1/pom.xml");
+        assertTrue(Files.exists(pathPom));
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/multi-module-wrapper/camel-karaf/b1-pom-expected.xml")),
+                Files.readString(pathPom));
+        assertTrue(Files.exists(camelKarafComponentRoot.resolve("camel-b/camel-b2/pom.xml")));
+        assertTrue(Files.exists(camelKarafComponentRoot.resolve("camel-b/camel-b3/pom.xml")));
+        handler.remove("camel-b", "camel-b1");
+        assertFalse(Files.exists(camelKarafComponentRoot.resolve("camel-b/camel-b1")));
+        handler.remove("camel-b", "camel-b2");
+        assertFalse(Files.exists(camelKarafComponentRoot.resolve("camel-b/camel-b2")));
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/multi-module-wrapper/camel-karaf/b-pom-after-remove-expected.xml")),
+                Files.readString(pathPomB));
+        handler.remove("camel-b", "camel-b3");
+        assertFalse(Files.exists(camelKarafComponentRoot.resolve("camel-b")));
+        assertEquals(
+                Files.readString(Paths.get("src/test/resources/multi-module-wrapper/camel-karaf/pom.xml")),
+                Files.readString(pathRootPom));
+    }
+}
diff --git a/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/ParentPomUpdaterTest.java b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/ParentPomUpdaterTest.java
new file mode 100644
index 00000000..42c42984
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/ParentPomUpdaterTest.java
@@ -0,0 +1,77 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Unit test for {@link ParentPomUpdater}.
+ */
+class ParentPomUpdaterTest {
+
+    @DisplayName("Should fail when the Camel's pom file doesn't contain the starting pattern")
+    @Test
+    void noStartInCamel() {
+        ParentPomUpdater updater = new ParentPomUpdater(
+                Paths.get("target/test-classes/parent-pom-updater/camel-karaf-pom-no-start.xml"),
+                Paths.get("target/test-classes/parent-pom-updater/camel-pom-no-start.xml"),
+                "4.1.0");
+        assertThrows(IllegalStateException.class, updater::execute);
+    }
+
+    @DisplayName("Should fail when the Camel Karaf's pom file doesn't contain the starting pattern")
+    @Test
+    void noStartInCamelKaraf() {
+        ParentPomUpdater updater = new ParentPomUpdater(
+                Paths.get("target/test-classes/parent-pom-updater/camel-karaf-pom-no-start.xml"),
+                Paths.get("target/test-classes/parent-pom-updater/camel-pom.xml"),
+                "4.1.0");
+        assertThrows(IllegalStateException.class, updater::execute);
+    }
+
+    @DisplayName("Should fail when the Camel Karaf's pom file doesn't contain the ending pattern")
+    @Test
+    void noEndInCamelKaraf() {
+        ParentPomUpdater updater = new ParentPomUpdater(
+                Paths.get("target/test-classes/parent-pom-updater/camel-karaf-pom-no-end.xml"),
+                Paths.get("target/test-classes/parent-pom-updater/camel-pom.xml"),
+                "4.1.0");
+        assertThrows(IllegalStateException.class, updater::execute);
+    }
+
+    @DisplayName("Should properly update the Camel Karaf's pom file as expected")
+    @Test
+    void updatePom() throws Exception {
+        ParentPomUpdater updater = new ParentPomUpdater(
+                Paths.get("target/test-classes/parent-pom-updater/camel-karaf-pom.xml"),
+                Paths.get("target/test-classes/parent-pom-updater/camel-pom.xml"),
+                "4.1.0");
+        updater.execute();
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/parent-pom-updater/camel-karaf-pom-expected.xml")),
+                Files.readString(Paths.get("target/test-classes/parent-pom-updater/camel-karaf-pom.xml")));
+    }
+
+}
diff --git a/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/PomUpdaterTest.java b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/PomUpdaterTest.java
new file mode 100644
index 00000000..b0680954
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/PomUpdaterTest.java
@@ -0,0 +1,47 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Unit test for {@link PomUpdater}.
+ */
+class PomUpdaterTest {
+
+    @Test
+    void testAll() throws Exception {
+        PomUpdater updater = new PomUpdater(Paths.get("target/test-classes/pom-updater"), "4.1.0");
+        updater.execute();
+        for (String path : List.of("pom.xml", "level2/pom.xml", "level2/level3/pom.xml")) {
+            assertEquals(
+                    Files.readString(Paths.get("target/test-classes/pom-updater/pom-expected.xml")),
+                    Files.readString(Paths.get("target/test-classes/pom-updater/%s".formatted(path))),
+                    "File %s doesn't match with the expected content".formatted(path));
+        }
+        assertEquals(
+                Files.readString(Paths.get("src/test/resources/pom-updater/src/pom.xml")),
+                Files.readString(Paths.get("target/test-classes/pom-updater/src/pom.xml")));
+    }
+}
diff --git a/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/SingleModuleWrapperHandlerTest.java b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/SingleModuleWrapperHandlerTest.java
new file mode 100644
index 00000000..6c885132
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/java/org/apache/camel/karaf/tooling/upgrade/SingleModuleWrapperHandlerTest.java
@@ -0,0 +1,68 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.karaf.tooling.upgrade;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit test for {@link SingleModuleWrapperHandler}.
+ */
+class SingleModuleWrapperHandlerTest {
+
+    @Test
+    void testAll() throws Exception {
+        SingleModuleWrapperHandler handler = new SingleModuleWrapperHandler(
+                Paths.get("target/test-classes/single-module-wrapper/camel-karaf"),
+                Paths.get("target/test-classes/single-module-wrapper/camel"),
+                "4.0.0");
+        handler.add("camel-a");
+        Path pathPom = Paths.get("target/test-classes/single-module-wrapper/camel-karaf/camel-a/pom.xml");
+        assertTrue(Files.exists(pathPom));
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/a-pom-expected.xml")),
+                Files.readString(pathPom));
+        handler.add("camel-c");
+        pathPom = Paths.get("target/test-classes/single-module-wrapper/camel-karaf/camel-c/pom.xml");
+        assertTrue(Files.exists(pathPom));
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/c-pom-expected.xml")),
+                Files.readString(pathPom));
+        handler.add("camel-e");
+        assertTrue(Files.exists(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/camel-e/pom.xml")));
+        assertEquals(
+                Files.readString(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/pom-expected.xml")),
+                Files.readString(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/pom.xml")));
+        handler.remove("camel-c");
+        assertFalse(Files.exists(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/camel-c")));
+        handler.remove("camel-e");
+        assertFalse(Files.exists(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/camel-e")));
+        handler.remove("camel-a");
+        assertFalse(Files.exists(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/camel-a")));
+        assertEquals(
+                Files.readString(Paths.get("src/test/resources/single-module-wrapper/camel-karaf/pom.xml")),
+                Files.readString(Paths.get("target/test-classes/single-module-wrapper/camel-karaf/pom.xml")));
+    }
+}
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-multiple/camel-both-multiple-a/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-multiple/camel-both-multiple-a/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-multiple/camel-both-multiple-b/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-multiple/camel-both-multiple-b/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-multiple/src/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-multiple/src/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-single/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-both-single/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-multiple/camel-karaf-multiple-a/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-multiple/camel-karaf-multiple-a/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-multiple/camel-karaf-multiple-b/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-multiple/camel-karaf-multiple-b/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-multiple/camel-karaf-multiple-only/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-multiple/camel-karaf-multiple-only/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-only/.keep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-karaf-only/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-multiple/camel-multiple-a/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-multiple/camel-multiple-a/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-multiple/camel-multiple-b/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel-karaf/camel-multiple/camel-multiple-b/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-both-multiple/camel-both-multiple-a/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-both-multiple/camel-both-multiple-a/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-both-multiple/camel-both-multiple-b/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-both-multiple/camel-both-multiple-b/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-both-single/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-both-single/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-a/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-a/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-api/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-api/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-b/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-b/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-codegen/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-codegen/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-component/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-component/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-maven-plugin/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-maven-plugin/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-spi/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-multiple/camel-complex-multiple-spi/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-api/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-api/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-codegen/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-codegen/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-component/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-component/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-maven-plugin/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-maven-plugin/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-spi/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-complex-single/camel-complex-single-spi/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-karaf-multiple/camel-karaf-multiple-a/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-karaf-multiple/camel-karaf-multiple-a/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-karaf-multiple/camel-karaf-multiple-b/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-karaf-multiple/camel-karaf-multiple-b/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-multiple/camel-multiple-a/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-multiple/camel-multiple-a/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-multiple/camel-multiple-b/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-multiple/camel-multiple-b/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-multiple/camel-multiple-only/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-multiple/camel-multiple-only/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-only/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/camel-only/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/comparator/camel/src/.gitkeep b/tooling/camel-upgrade/src/test/resources/comparator/camel/src/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/default-values/empty.properties b/tooling/camel-upgrade/src/test/resources/default-values/empty.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/default-values/full.properties b/tooling/camel-upgrade/src/test/resources/default-values/full.properties
new file mode 100644
index 00000000..cdaadf1d
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/default-values/full.properties
@@ -0,0 +1,20 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+camel.version = 4.0.0
+camel.karaf.root = camel-karaf-root
+camel.root = camel-root
\ No newline at end of file
diff --git a/tooling/camel-upgrade/src/test/resources/features/empty.xml b/tooling/camel-upgrade/src/test/resources/features/empty.xml
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/features/inject-after-expected.xml b/tooling/camel-upgrade/src/test/resources/features/inject-after-expected.xml
new file mode 100644
index 00000000..f4462989
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/inject-after-expected.xml
@@ -0,0 +1,59 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-d' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-d/${project.version}</bundle>
+    </feature>
+    <feature name='camel-e' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-core</feature>
+        <bundle>mvn:org.apache.camel.karaf/camel-e/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/inject-after.xml b/tooling/camel-upgrade/src/test/resources/features/inject-after.xml
new file mode 100644
index 00000000..c1787e6d
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/inject-after.xml
@@ -0,0 +1,55 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-d' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-d/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/inject-before-expected.xml b/tooling/camel-upgrade/src/test/resources/features/inject-before-expected.xml
new file mode 100644
index 00000000..ad7bae00
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/inject-before-expected.xml
@@ -0,0 +1,59 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-a' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-core</feature>
+        <bundle>mvn:org.apache.camel.karaf/camel-a/${project.version}</bundle>
+    </feature>
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-d' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-d/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/inject-before.xml b/tooling/camel-upgrade/src/test/resources/features/inject-before.xml
new file mode 100644
index 00000000..c1787e6d
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/inject-before.xml
@@ -0,0 +1,55 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-d' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-d/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/inject-middle-expected.xml b/tooling/camel-upgrade/src/test/resources/features/inject-middle-expected.xml
new file mode 100644
index 00000000..a3fd4c58
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/inject-middle-expected.xml
@@ -0,0 +1,59 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-c' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-core</feature>
+        <bundle>mvn:org.apache.camel.karaf/camel-c/${project.version}</bundle>
+    </feature>
+    <feature name='camel-d' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-d/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/inject-middle.xml b/tooling/camel-upgrade/src/test/resources/features/inject-middle.xml
new file mode 100644
index 00000000..c1787e6d
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/inject-middle.xml
@@ -0,0 +1,55 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-d' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-d/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/remove-after-expected.xml b/tooling/camel-upgrade/src/test/resources/features/remove-after-expected.xml
new file mode 100644
index 00000000..d4f4e815
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/remove-after-expected.xml
@@ -0,0 +1,55 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-a' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-a/${project.version}</bundle>
+    </feature>
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/remove-after.xml b/tooling/camel-upgrade/src/test/resources/features/remove-after.xml
new file mode 100644
index 00000000..77f8e3fd
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/remove-after.xml
@@ -0,0 +1,61 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-a' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-a/${project.version}</bundle>
+    </feature>
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-c' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-c/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/remove-before-expected.xml b/tooling/camel-upgrade/src/test/resources/features/remove-before-expected.xml
new file mode 100644
index 00000000..cfd0bf1b
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/remove-before-expected.xml
@@ -0,0 +1,55 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-c' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-c/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/remove-before.xml b/tooling/camel-upgrade/src/test/resources/features/remove-before.xml
new file mode 100644
index 00000000..77f8e3fd
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/remove-before.xml
@@ -0,0 +1,61 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-a' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-a/${project.version}</bundle>
+    </feature>
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-c' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-c/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/remove-middle-expected.xml b/tooling/camel-upgrade/src/test/resources/features/remove-middle-expected.xml
new file mode 100644
index 00000000..5d175476
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/remove-middle-expected.xml
@@ -0,0 +1,55 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-a' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-a/${project.version}</bundle>
+    </feature>
+    <feature name='camel-c' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-c/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/camel-upgrade/src/test/resources/features/remove-middle.xml b/tooling/camel-upgrade/src/test/resources/features/remove-middle.xml
new file mode 100644
index 00000000..77f8e3fd
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/features/remove-middle.xml
@@ -0,0 +1,61 @@
+<?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.
+
+-->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="camel-${project.version}">
+
+    <!-- TODO: specs will be provided by Apache Karaf 4.5.x spec features repository. However, in order to have Camel 4.x working on Karaf 4.4.x, we define spec features here -->
+    <feature name="jakarta-activation" version="${jakarta-activation-version}">
+        <bundle dependency="true">mvn:jakarta.activation/jakarta.activation-api/${jakarta-activation-version}</bundle>
+    </feature>
+
+    <!-- Apache Camel core features -->
+
+    <feature name="camel" version="${project.version}" start-level="50">
+        <feature prerequisite="true">wrap</feature>
+        <feature version="${camel-osgi-version-range}">camel-core</feature>
+        <feature version="${camel-osgi-version-range}">camel-blueprint</feature>
+    </feature>
+
+    <feature name="camel-core" version="${project.version}" start-level="50">
+        <feature version="[${servicemix-specs-version},11)">xml-specs-api</feature>
+        <bundle dependency="true">mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    </feature>
+
+    <!-- the following features are sorted A..Z -->
+
+    <feature name='camel-a' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-a/${project.version}</bundle>
+    </feature>
+    <feature name='camel-b' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-b/${project.version}</bundle>
+    </feature>
+    <feature name='camel-c' version='${project.version}' start-level='50'>
+        <feature version='${camel-osgi-version-range}'>camel-jms</feature>
+        <bundle dependency='true'>mvn:org.apache.activemq/activemq-client/${activemq-version}</bundle>
+        <bundle dependency='true'>mvn:org.fusesource.hawtbuf/hawtbuf/${auto-detect-version}</bundle>
+        <bundle>mvn:org.apache.camel.karaf/camel-c/${project.version}</bundle>
+    </feature>
+
+</features>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b-pom-after-remove-expected.xml
similarity index 77%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b-pom-after-remove-expected.xml
index 6cc35313..917accae 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b-pom-after-remove-expected.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -16,21 +18,21 @@
 
 -->
 <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
-    
+
     <parent>
         <groupId>org.apache.camel.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <artifactId>camel-karaf-components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    
-    <artifactId>tooling</artifactId>
+
+    <artifactId>camel-b-parent</artifactId>
     <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
+    <name>Apache Camel :: Karaf :: Components :: B :: Parent</name>
+
     <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>camel-b3</module>
     </modules>
-    
-</project>
\ No newline at end of file
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b-pom-expected.xml
similarity index 74%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b-pom-expected.xml
index 6cc35313..4c17d5e7 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b-pom-expected.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -16,21 +18,23 @@
 
 -->
 <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
-    
+
     <parent>
         <groupId>org.apache.camel.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <artifactId>camel-karaf-components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    
-    <artifactId>tooling</artifactId>
+
+    <artifactId>camel-b-parent</artifactId>
     <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
+    <name>Apache Camel :: Karaf :: Components :: B :: Parent</name>
+
     <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>camel-b1</module>
+        <module>camel-b2</module>
+        <module>camel-b3</module>
     </modules>
-    
-</project>
\ No newline at end of file
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b1-pom-expected.xml b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b1-pom-expected.xml
new file mode 100644
index 00000000..bb0e73e7
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/b1-pom-expected.xml
@@ -0,0 +1,81 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.karaf</groupId>
+        <artifactId>camel-b-parent</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-b1</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Camel :: Karaf :: Components :: B :: B1</name>
+
+    <properties>
+        <camel.osgi.export>
+            org.apache.camel*;version=${camel-version}
+        </camel.osgi.export>
+        <camel.osgi.import>
+            *
+        </camel.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-b1</artifactId>
+            <version>${camel-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.camel:camel-b1</include>
+                                </includes>
+                            </artifactSet>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/expected-pom.xml
similarity index 78%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/expected-pom.xml
index 6cc35313..187072f9 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/expected-pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -16,21 +18,23 @@
 
 -->
 <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
-    
+
     <parent>
         <groupId>org.apache.camel.karaf</groupId>
         <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    
-    <artifactId>tooling</artifactId>
+
+    <artifactId>camel-karaf-components</artifactId>
     <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
+    <name>Apache Camel :: Karaf :: Components</name>
+
     <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>camel-a</module>
+        <module>camel-b</module>
+        <module>camel-c</module>
     </modules>
-    
-</project>
\ No newline at end of file
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/pom.xml
similarity index 79%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/pom.xml
index 6cc35313..41575e36 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel-karaf/pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -16,21 +18,22 @@
 
 -->
 <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
-    
+
     <parent>
         <groupId>org.apache.camel.karaf</groupId>
         <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    
-    <artifactId>tooling</artifactId>
+
+    <artifactId>camel-karaf-components</artifactId>
     <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
+    <name>Apache Camel :: Karaf :: Components</name>
+
     <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>camel-a</module>
+        <module>camel-c</module>
     </modules>
-    
-</project>
\ No newline at end of file
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel/.gitkeep b/tooling/camel-upgrade/src/test/resources/multi-module-wrapper/camel/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-expected.xml b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-expected.xml
new file mode 100644
index 00000000..d0667ffa
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-expected.xml
@@ -0,0 +1,78 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache</groupId>
+        <artifactId>apache</artifactId>
+        <version>31</version>
+    </parent>
+
+    <groupId>org.apache.camel.karaf</groupId>
+    <artifactId>camel-karaf</artifactId>
+    <version>4.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <jdk-version>17</jdk-version>
+
+        <camel-version>4.1.0</camel-version>
+
+        <!-- START: Maven Properties defining the version of 3rd party libraries used in Camel -->
+        <activemq-version>5.18.4</activemq-version>
+        <activemq-artemis-version>2.33.0</activemq-artemis-version>
+        <angus-mail-version>2.0.3</angus-mail-version>
+        <apacheds-version>2.0.0.AM26</apacheds-version>
+        <apache-drill-version>1.21.1</apache-drill-version>
+        <picocli-version>4.7.5</picocli-version>
+        <metrics-version>4.2.25</metrics-version>
+        <xml-apis-version>1.4.01</xml-apis-version>
+        <zeebe-version>8.5.0</zeebe-version>
+        <zendesk-client-version>0.25.0</zendesk-client-version>
+        <zookeeper-version>3.9.2</zookeeper-version>
+        <zxing-version>3.5.3</zxing-version>
+        <!-- END: Maven Properties defining the version of 3rd party libraries used in Camel -->
+
+        <!-- OSGI version ranges -->
+        <camel-osgi-asm-version>[9.5,10)</camel-osgi-asm-version>
+        <camel-osgi-cglib-version>[3.3,3.4)</camel-osgi-cglib-version>
+        <camel-osgi-jackson2-version>[2.17,2.18)</camel-osgi-jackson2-version>
+
+        <!-- Camel Karaf OSGI version ranges -->
+        <camel-osgi-version-clean>4.1</camel-osgi-version-clean>
+        <camel-osgi-next-version-clean>4.2</camel-osgi-next-version-clean>
+        <camel-osgi-version-range>[${camel-osgi-version-clean},${camel-osgi-next-version-clean})</camel-osgi-version-range>
+        <camel-osgi-import-camel-version>version="${camel-osgi-version-range}"</camel-osgi-import-camel-version>
+        <camel-osgi-camel-import>org.apache.camel.*;${camel-osgi-import-camel-version},</camel-osgi-camel-import>
+
+        <!-- Other dependencies version not inherited from Camel -->
+        <angus-activation-version>2.0.2</angus-activation-version>
+        <aries-util-version>1.1.3</aries-util-version>
+        <aries-version>1.10.3</aries-version>
+
+        <!-- Plugin versions -->
+        <maven-bundle-plugin-version>5.1.9</maven-bundle-plugin-version>
+        <maven-compiler-plugin-version>3.13.0</maven-compiler-plugin-version>
+        <maven-dependency-plugin-version>3.7.0</maven-dependency-plugin-version>
+    </properties>
+
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-camel-start.xml b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-camel-start.xml
new file mode 100644
index 00000000..af8c3d6d
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-camel-start.xml
@@ -0,0 +1,72 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache</groupId>
+        <artifactId>apache</artifactId>
+        <version>31</version>
+    </parent>
+
+    <groupId>org.apache.camel.karaf</groupId>
+    <artifactId>camel-karaf</artifactId>
+    <version>4.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <jdk-version>17</jdk-version>
+
+        <camel-version>4.0.0</camel-version>
+
+        <!-- START: Maven Properties defining the version of 3rd party libraries used in Camel -->
+        <activemq-version>6.1.2</activemq-version>
+        <activemq-artemis-version>2.33.0</activemq-artemis-version>
+        <angus-mail-version>2.0.3</angus-mail-version>
+        <apacheds-version>2.0.0.AM20</apacheds-version>
+        <zendesk-client-version>0.20.0</zendesk-client-version>
+        <zookeeper-version>3.9.2</zookeeper-version>
+        <!-- END: Maven Properties defining the version of 3rd party libraries used in Camel -->
+
+        <!-- OSGI version ranges -->
+        <camel-osgi-asm-version>[9.5,10)</camel-osgi-asm-version>
+        <camel-osgi-cglib-version>[3.3,3.4)</camel-osgi-cglib-version>
+        <camel-osgi-jackson2-version>[2.17,2.18)</camel-osgi-jackson2-version>
+
+        <!-- Camel Karaf OSGI version ranges -->
+        <camel-osgi-version-clean>4.0</camel-osgi-version-clean>
+        <camel-osgi-next-version-clean>4.1</camel-osgi-next-version-clean>
+        <camel-osgi-version-range>[${camel-osgi-version-clean},${camel-osgi-next-version-clean})</camel-osgi-version-range>
+        <camel-osgi-import-camel-version>version="${camel-osgi-version-range}"</camel-osgi-import-camel-version>
+        <camel-osgi-camel-import>org.apache.camel.*;${camel-osgi-import-camel-version},</camel-osgi-camel-import>
+
+        <!-- Other dependencies version not inherited from Camel -->
+        <angus-activation-version>2.0.2</angus-activation-version>
+        <aries-util-version>1.1.3</aries-util-version>
+        <aries-version>1.10.3</aries-version>
+
+        <!-- Plugin versions -->
+        <maven-bundle-plugin-version>5.1.9</maven-bundle-plugin-version>
+        <maven-compiler-plugin-version>3.13.0</maven-compiler-plugin-version>
+        <maven-dependency-plugin-version>3.7.0</maven-dependency-plugin-version>
+    </properties>
+
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-end.xml b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-end.xml
new file mode 100644
index 00000000..cf8d9fde
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-end.xml
@@ -0,0 +1,71 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache</groupId>
+        <artifactId>apache</artifactId>
+        <version>31</version>
+    </parent>
+
+    <groupId>org.apache.camel.karaf</groupId>
+    <artifactId>camel-karaf</artifactId>
+    <version>4.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <jdk-version>17</jdk-version>
+
+        <camel-version>4.0.0</camel-version>
+
+        <!-- START: Maven Properties defining the version of 3rd party libraries used in Camel -->
+        <activemq-version>6.1.2</activemq-version>
+        <activemq-artemis-version>2.33.0</activemq-artemis-version>
+        <angus-mail-version>2.0.3</angus-mail-version>
+        <apacheds-version>2.0.0.AM20</apacheds-version>
+        <zendesk-client-version>0.20.0</zendesk-client-version>
+        <zookeeper-version>3.9.2</zookeeper-version>
+
+        <!-- OSGI version ranges -->
+        <camel-osgi-asm-version>[9.5,10)</camel-osgi-asm-version>
+        <camel-osgi-cglib-version>[3.3,3.4)</camel-osgi-cglib-version>
+        <camel-osgi-jackson2-version>[2.17,2.18)</camel-osgi-jackson2-version>
+
+        <!-- Camel Karaf OSGI version ranges -->
+        <camel-osgi-version-clean>4.0</camel-osgi-version-clean>
+        <camel-osgi-next-version-clean>4.1</camel-osgi-next-version-clean>
+        <camel-osgi-version-range>[${camel-osgi-version-clean},${camel-osgi-next-version-clean})</camel-osgi-version-range>
+        <camel-osgi-import-camel-version>version="${camel-osgi-version-range}"</camel-osgi-import-camel-version>
+        <camel-osgi-camel-import>org.apache.camel.*;${camel-osgi-import-camel-version},</camel-osgi-camel-import>
+
+        <!-- Other dependencies version not inherited from Camel -->
+        <angus-activation-version>2.0.2</angus-activation-version>
+        <aries-util-version>1.1.3</aries-util-version>
+        <aries-version>1.10.3</aries-version>
+
+        <!-- Plugin versions -->
+        <maven-bundle-plugin-version>5.1.9</maven-bundle-plugin-version>
+        <maven-compiler-plugin-version>3.13.0</maven-compiler-plugin-version>
+        <maven-dependency-plugin-version>3.7.0</maven-dependency-plugin-version>
+    </properties>
+
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-start.xml b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-start.xml
new file mode 100644
index 00000000..46565191
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom-no-start.xml
@@ -0,0 +1,71 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache</groupId>
+        <artifactId>apache</artifactId>
+        <version>31</version>
+    </parent>
+
+    <groupId>org.apache.camel.karaf</groupId>
+    <artifactId>camel-karaf</artifactId>
+    <version>4.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <jdk-version>17</jdk-version>
+
+        <camel-version>4.0.0</camel-version>
+
+        <activemq-version>6.1.2</activemq-version>
+        <activemq-artemis-version>2.33.0</activemq-artemis-version>
+        <angus-mail-version>2.0.3</angus-mail-version>
+        <apacheds-version>2.0.0.AM20</apacheds-version>
+        <zendesk-client-version>0.20.0</zendesk-client-version>
+        <zookeeper-version>3.9.2</zookeeper-version>
+        <!-- END: Maven Properties defining the version of 3rd party libraries used in Camel -->
+
+        <!-- OSGI version ranges -->
+        <camel-osgi-asm-version>[9.5,10)</camel-osgi-asm-version>
+        <camel-osgi-cglib-version>[3.3,3.4)</camel-osgi-cglib-version>
+        <camel-osgi-jackson2-version>[2.17,2.18)</camel-osgi-jackson2-version>
+
+        <!-- Camel Karaf OSGI version ranges -->
+        <camel-osgi-version-clean>4.0</camel-osgi-version-clean>
+        <camel-osgi-next-version-clean>4.1</camel-osgi-next-version-clean>
+        <camel-osgi-version-range>[${camel-osgi-version-clean},${camel-osgi-next-version-clean})</camel-osgi-version-range>
+        <camel-osgi-import-camel-version>version="${camel-osgi-version-range}"</camel-osgi-import-camel-version>
+        <camel-osgi-camel-import>org.apache.camel.*;${camel-osgi-import-camel-version},</camel-osgi-camel-import>
+
+        <!-- Other dependencies version not inherited from Camel -->
+        <angus-activation-version>2.0.2</angus-activation-version>
+        <aries-util-version>1.1.3</aries-util-version>
+        <aries-version>1.10.3</aries-version>
+
+        <!-- Plugin versions -->
+        <maven-bundle-plugin-version>5.1.9</maven-bundle-plugin-version>
+        <maven-compiler-plugin-version>3.13.0</maven-compiler-plugin-version>
+        <maven-dependency-plugin-version>3.7.0</maven-dependency-plugin-version>
+    </properties>
+
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom.xml b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom.xml
new file mode 100644
index 00000000..af8c3d6d
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-karaf-pom.xml
@@ -0,0 +1,72 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache</groupId>
+        <artifactId>apache</artifactId>
+        <version>31</version>
+    </parent>
+
+    <groupId>org.apache.camel.karaf</groupId>
+    <artifactId>camel-karaf</artifactId>
+    <version>4.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <jdk-version>17</jdk-version>
+
+        <camel-version>4.0.0</camel-version>
+
+        <!-- START: Maven Properties defining the version of 3rd party libraries used in Camel -->
+        <activemq-version>6.1.2</activemq-version>
+        <activemq-artemis-version>2.33.0</activemq-artemis-version>
+        <angus-mail-version>2.0.3</angus-mail-version>
+        <apacheds-version>2.0.0.AM20</apacheds-version>
+        <zendesk-client-version>0.20.0</zendesk-client-version>
+        <zookeeper-version>3.9.2</zookeeper-version>
+        <!-- END: Maven Properties defining the version of 3rd party libraries used in Camel -->
+
+        <!-- OSGI version ranges -->
+        <camel-osgi-asm-version>[9.5,10)</camel-osgi-asm-version>
+        <camel-osgi-cglib-version>[3.3,3.4)</camel-osgi-cglib-version>
+        <camel-osgi-jackson2-version>[2.17,2.18)</camel-osgi-jackson2-version>
+
+        <!-- Camel Karaf OSGI version ranges -->
+        <camel-osgi-version-clean>4.0</camel-osgi-version-clean>
+        <camel-osgi-next-version-clean>4.1</camel-osgi-next-version-clean>
+        <camel-osgi-version-range>[${camel-osgi-version-clean},${camel-osgi-next-version-clean})</camel-osgi-version-range>
+        <camel-osgi-import-camel-version>version="${camel-osgi-version-range}"</camel-osgi-import-camel-version>
+        <camel-osgi-camel-import>org.apache.camel.*;${camel-osgi-import-camel-version},</camel-osgi-camel-import>
+
+        <!-- Other dependencies version not inherited from Camel -->
+        <angus-activation-version>2.0.2</angus-activation-version>
+        <aries-util-version>1.1.3</aries-util-version>
+        <aries-version>1.10.3</aries-version>
+
+        <!-- Plugin versions -->
+        <maven-bundle-plugin-version>5.1.9</maven-bundle-plugin-version>
+        <maven-compiler-plugin-version>3.13.0</maven-compiler-plugin-version>
+        <maven-dependency-plugin-version>3.7.0</maven-dependency-plugin-version>
+    </properties>
+
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-pom-no-start.xml b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-pom-no-start.xml
new file mode 100644
index 00000000..a21c4e0a
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-pom-no-start.xml
@@ -0,0 +1,68 @@
+<?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>camel</artifactId>
+        <version>4.0.0</version>
+    </parent>
+
+    <artifactId>camel-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Camel :: Parent</name>
+    <description>Camel Parent POM</description>
+
+    <properties>
+        <maven.build.timestamp.format>yyyy-MM-dd</maven.build.timestamp.format>
+        <camel.surefire.fork.additional-vmargs /><!-- Empty by default -->
+        <camel.surefire.fork.vmargs>-XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError ${camel.surefire.fork.additional-vmargs}</camel.surefire.fork.vmargs>
+        <camel.surefire.forkCount>1</camel.surefire.forkCount>
+
+        <cxf.xjc.jvmArgs />
+        <trimStackTrace>false</trimStackTrace>
+        <sourcecheckExcludes />
+        <sourcecheckExcludesComma />
+
+        <activemq-version>5.18.4</activemq-version>
+        <activemq-artemis-version>2.33.0</activemq-artemis-version>
+        <angus-mail-version>2.0.3</angus-mail-version>
+        <apacheds-version>2.0.0.AM26</apacheds-version>
+        <apache-drill-version>1.21.1</apache-drill-version>
+        <!-- needed from tooling/archetypes -->
+        <maven-version>3.9.6</maven-version>
+        <maven-antrun-plugin-version>3.1.0</maven-antrun-plugin-version>
+        <maven-archetype-plugin-version>3.2.1</maven-archetype-plugin-version>
+        <maven-archetype-packaging-version>3.2.1</maven-archetype-packaging-version>
+        <!-- resources plugin needed by Camel maven archetypes -->
+        <maven-resources-plugin-version>3.3.1</maven-resources-plugin-version>
+        <maven-reporting-api-version>3.1.1</maven-reporting-api-version>
+        <maven-reporting-impl-version>3.2.0</maven-reporting-impl-version>
+        <metrics-version>4.2.25</metrics-version>
+        <!-- needed to manage the xml-apis version in camel-xmljson -->
+        <xml-apis-version>1.4.01</xml-apis-version>
+        <zendesk-client-version>0.25.0</zendesk-client-version>
+        <zookeeper-version>3.9.2</zookeeper-version>
+        <zxing-version>3.5.3</zxing-version>
+    </properties>
+
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-pom.xml b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-pom.xml
new file mode 100644
index 00000000..d4159a63
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/parent-pom-updater/camel-pom.xml
@@ -0,0 +1,73 @@
+<?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>camel</artifactId>
+        <version>4.0.0</version>
+    </parent>
+
+    <artifactId>camel-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Camel :: Parent</name>
+    <description>Camel Parent POM</description>
+
+    <properties>
+        <maven.build.timestamp.format>yyyy-MM-dd</maven.build.timestamp.format>
+        <camel.surefire.fork.additional-vmargs /><!-- Empty by default -->
+        <camel.surefire.fork.vmargs>-XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError ${camel.surefire.fork.additional-vmargs}</camel.surefire.fork.vmargs>
+        <camel.surefire.forkCount>1</camel.surefire.forkCount>
+
+        <cxf.xjc.jvmArgs />
+        <trimStackTrace>false</trimStackTrace>
+        <sourcecheckExcludes />
+        <sourcecheckExcludesComma />
+
+        <!-- dependency versions -->
+        <activemq-version>5.18.4</activemq-version>
+        <activemq-artemis-version>2.33.0</activemq-artemis-version>
+        <angus-mail-version>2.0.3</angus-mail-version>
+        <apacheds-version>2.0.0.AM26</apacheds-version>
+        <apache-drill-version>1.21.1</apache-drill-version>
+
+  <picocli-version>4.7.5</picocli-version>
+
+        <!-- needed from tooling/archetypes -->
+        <maven-version>3.9.6</maven-version>
+        <maven-antrun-plugin-version>3.1.0</maven-antrun-plugin-version>
+        <maven-archetype-plugin-version>3.2.1</maven-archetype-plugin-version>
+        <maven-archetype-packaging-version>3.2.1</maven-archetype-packaging-version>
+        <!-- resources plugin needed by Camel maven archetypes -->
+        <maven-resources-plugin-version>3.3.1</maven-resources-plugin-version>
+        <maven-reporting-api-version>3.1.1</maven-reporting-api-version>
+        <maven-reporting-impl-version>3.2.0</maven-reporting-impl-version>
+        <metrics-version>4.2.25</metrics-version>
+        <!-- needed to manage the xml-apis version in camel-xmljson -->
+        <xml-apis-version>1.4.01</xml-apis-version>
+        <zeebe.version>8.5.0</zeebe.version>
+        <zendesk-client-version>0.25.0</zendesk-client-version>
+        <zookeeper-version>3.9.2</zookeeper-version>
+        <zxing-version>3.5.3</zxing-version>
+    </properties>
+
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/pom-updater/level2/level3/pom.xml
similarity index 56%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/pom-updater/level2/level3/pom.xml
index 6cc35313..4c20de9f 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/pom-updater/level2/level3/pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -15,22 +17,30 @@
     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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<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.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
     </parent>
-    
-    <artifactId>tooling</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
-    <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
-    </modules>
-    
-</project>
\ No newline at end of file
+
+    <artifactId>camel-a</artifactId>
+    <packaging>jar</packaging>
+    <version>4.0.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.16.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-api</artifactId>
+            <version>4.0.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/pom-updater/level2/pom.xml
similarity index 56%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/pom-updater/level2/pom.xml
index 6cc35313..4c20de9f 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/pom-updater/level2/pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -15,22 +17,30 @@
     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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<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.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
     </parent>
-    
-    <artifactId>tooling</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
-    <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
-    </modules>
-    
-</project>
\ No newline at end of file
+
+    <artifactId>camel-a</artifactId>
+    <packaging>jar</packaging>
+    <version>4.0.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.16.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-api</artifactId>
+            <version>4.0.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/pom-updater/pom-expected.xml
similarity index 56%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/pom-updater/pom-expected.xml
index 6cc35313..1e991629 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/pom-updater/pom-expected.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -15,22 +17,30 @@
     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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<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.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.1.0-SNAPSHOT</version>
     </parent>
-    
-    <artifactId>tooling</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
-    <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
-    </modules>
-    
-</project>
\ No newline at end of file
+
+    <artifactId>camel-a</artifactId>
+    <packaging>jar</packaging>
+    <version>4.1.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.16.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-api</artifactId>
+            <version>4.1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/pom-updater/pom.xml
similarity index 56%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/pom-updater/pom.xml
index 6cc35313..4c20de9f 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/pom-updater/pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -15,22 +17,30 @@
     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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<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.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
     </parent>
-    
-    <artifactId>tooling</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
-    <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
-    </modules>
-    
-</project>
\ No newline at end of file
+
+    <artifactId>camel-a</artifactId>
+    <packaging>jar</packaging>
+    <version>4.0.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.16.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-api</artifactId>
+            <version>4.0.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/pom-updater/src/pom.xml
similarity index 56%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/pom-updater/src/pom.xml
index 6cc35313..4c20de9f 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/pom-updater/src/pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -15,22 +17,30 @@
     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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<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.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
     </parent>
-    
-    <artifactId>tooling</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
-    <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
-    </modules>
-    
-</project>
\ No newline at end of file
+
+    <artifactId>camel-a</artifactId>
+    <packaging>jar</packaging>
+    <version>4.0.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.16.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-api</artifactId>
+            <version>4.0.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/a-pom-expected.xml b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/a-pom-expected.xml
new file mode 100644
index 00000000..067d4577
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/a-pom-expected.xml
@@ -0,0 +1,81 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.karaf</groupId>
+        <artifactId>camel-karaf-components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-a</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Camel :: Karaf :: Components :: Some Specific Name for A</name>
+
+    <properties>
+        <camel.osgi.export>
+            org.apache.camel*;version=${camel-version}
+        </camel.osgi.export>
+        <camel.osgi.import>
+            *
+        </camel.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-a</artifactId>
+            <version>${camel-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.camel:camel-a</include>
+                                </includes>
+                            </artifactSet>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/c-pom-expected.xml b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/c-pom-expected.xml
new file mode 100644
index 00000000..01d2ad85
--- /dev/null
+++ b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/c-pom-expected.xml
@@ -0,0 +1,81 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.karaf</groupId>
+        <artifactId>camel-karaf-components</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-c</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Camel :: Karaf :: Components :: C</name>
+
+    <properties>
+        <camel.osgi.export>
+            org.apache.camel*;version=${camel-version}
+        </camel.osgi.export>
+        <camel.osgi.import>
+            *
+        </camel.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-c</artifactId>
+            <version>${camel-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.camel:camel-c</include>
+                                </includes>
+                            </artifactSet>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/pom-expected.xml
similarity index 74%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/pom-expected.xml
index 6cc35313..0481ac38 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/pom-expected.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -16,21 +18,25 @@
 
 -->
 <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
-    
+
     <parent>
         <groupId>org.apache.camel.karaf</groupId>
         <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    
-    <artifactId>tooling</artifactId>
+
+    <artifactId>camel-karaf-components</artifactId>
     <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
+    <name>Apache Camel :: Karaf :: Components</name>
+
     <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>camel-a</module>
+        <module>camel-b</module>
+        <module>camel-c</module>
+        <module>camel-d</module>
+        <module>camel-e</module>
     </modules>
-    
-</project>
\ No newline at end of file
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/pom.xml
similarity index 79%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/pom.xml
index 6cc35313..200cd548 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel-karaf/pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -16,21 +18,22 @@
 
 -->
 <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
-    
+
     <parent>
         <groupId>org.apache.camel.karaf</groupId>
         <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    
-    <artifactId>tooling</artifactId>
+
+    <artifactId>camel-karaf-components</artifactId>
     <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
+    <name>Apache Camel :: Karaf :: Components</name>
+
     <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>camel-b</module>
+        <module>camel-d</module>
     </modules>
-    
-</project>
\ No newline at end of file
+</project>
diff --git a/tooling/pom.xml b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel/camel-a/pom.xml
similarity index 53%
copy from tooling/pom.xml
copy to tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel/camel-a/pom.xml
index 6cc35313..a365016d 100644
--- a/tooling/pom.xml
+++ b/tooling/camel-upgrade/src/test/resources/single-module-wrapper/camel/camel-a/pom.xml
@@ -1,4 +1,6 @@
+<?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.
@@ -15,22 +17,35 @@
     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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<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.karaf</groupId>
-        <artifactId>camel-karaf</artifactId>
-        <version>4.6.0-SNAPSHOT</version>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.0.0</version>
     </parent>
-    
-    <artifactId>tooling</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Camel :: Karaf :: Tooling</name>
-    
-    <modules>
-        <module>camel-karaf-feature-maven-plugin</module>
-        <module>camel-karaf-maven-plugin-integration-test</module>
-    </modules>
-    
-</project>
\ No newline at end of file
+
+    <artifactId>camel-a</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Camel :: Some Specific Name for A</name>
+    <description>A component for Camel</description>
+
+    <properties>
+        <camel.surefire.parallel>true</camel.surefire.parallel>
+
+        <!-- Artemis container is not available on these platforms -->
+        <skipITs.ppc64le>true</skipITs.ppc64le>
+        <skipITs.s390x>true</skipITs.s390x>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-jms</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/tooling/pom.xml b/tooling/pom.xml
index 6cc35313..f08fd9a6 100644
--- a/tooling/pom.xml
+++ b/tooling/pom.xml
@@ -27,10 +27,15 @@
     <artifactId>tooling</artifactId>
     <packaging>pom</packaging>
     <name>Apache Camel :: Karaf :: Tooling</name>
-    
+
+    <properties>
+        <maven-version>3.9.7</maven-version>
+    </properties>
+
     <modules>
         <module>camel-karaf-feature-maven-plugin</module>
         <module>camel-karaf-maven-plugin-integration-test</module>
+        <module>camel-upgrade</module>
     </modules>
     
 </project>
\ No newline at end of file