Upgrading a software application to a newer version is never a trivial task and leads often to a manual time-consuming process. That's why the Red Hat build of Apache Camel aims to simplify the process and minimize effort by offering tools for automated migration. The solution varies depending on the flavor of the project. Camel Extensions for Quarkus relies on different commands than the Camel for Spring Boot. The underlying layer takes advantage of the OpenRewrite ecosystem in both cases.
Basic concepts
Let’s concentrate on the basic aspects of the automatic migrations.
- Recipes
Recipes are the cornerstone of OpenRewrite. Recipe serves as a smallest unit covering a simple change in the source code. Recipes are cumulative and relate to a specific version. You can see recipes for Red Hat build of Apache Camel in the upstream repository . - Tool output
OpenRewrite tool logs information on the console output. There you can find details about source files modified by the recipes. - Limitations
Keep in mind that only the files within the project itself are migrated. In case that the BOM version is inherited i.e. through a parent module, the BOM version won’t be changed even though the sources of the project will be migrated to a target version. That may break the project until the parent module is migrated as well.
Red Hat build of Apache Camel on Quarkus
Upgrade of Camel Extensions for Quarkus is covered by the Quarkus CLI tool by running the update command, introduced in Red Hat build of Quarkus 2.13
The update command brings several benefits.
- Automates upgrade of project dependencies.
- Upgrades source code (in cases, where automatization can be applied).
- Allows migration to the latest LTS version while skipping some LTS streams entirely.
- The latest recipes are available to the CLI tool immediately with the new release.
Let’s explain a special endpoint used by Quarkus CLI tool for keeping track of released versions, called registry:
- Quarkus tooling has to be aware of the latest releases of Red Hat build of Quarkus and Camel Extensions for Quarkus (part of Red Hat build of Apache Camel). The update command contacts Quarkus registry to get up-to-date information about recent releases.
The Quarkus CLI tool drives the workflow of the recipes:
- Appropriate recipes are selected according to the registry, target version and the recipes version (more details are shared in the demo chapter). The selected recipes are handed over to the OpenRewrite tooling. OpenRewrite applies the recipes on the source code thereby upgrading it.
- The logged output shows the detailed information about the process itself.
A brief look at the upgrade guides, such as Apache Camel 3.x Upgrade Guide or Apache Camel 4.x Upgrade Guide confirms that upgrading can involve a significant amount of effort. Migrating across multiple versions of Camel is even more challenging and adds an extra amount of complexity to the process.
Demo time
Let’s not waste any more time with the theory and let’s better discuss a practical example of the Red Hat build of Apache Camel upgrade using Quarkus CLI.
The whole process is as simple as executing a single command from the root directory of the migrated project.
#Migration to the latest version of Camel Extensions for Quarkus (in the time of Red Hat build of Quarkus 3.15.2)
mvn io.quarkus.platform:quarkus-maven-plugin:3.15.2:update
The update command recognizes several parameters. Let’s mention the most important ones:
- stream - CLI tool migrates the application to the latest available version (of Red Hat build of Apache Camel) by default. To override such behavior, please append parameter
stream
to update the project to a particular stream. Here is the example of such command:
#Migrate to the latest version of Camel Extensions for Quarkus from stream 3.8.x
mvn io.quarkus.platform:quarkus-maven-plugin:3.15.2:update -Dstream=3.8
- quarkusUpdateRecipes - the update command applies the latest recipes distributed as a maven dependency
io.quarkus:quarkus-update-recipes
. The latest version is used by default. Sometimes, it might be handy to specify a different target version.
#Migrate to the latest version of Camel Extensions for Quarkus from stream 3.8.x using the specific version of recipes 1.0.22
mvn io.quarkus.platform:quarkus-maven-plugin:3.15.2:update -Dstream=3.15 -DquarkusUpdateRecipes=1.0.22
Let’s run a migration command on the testing project. The multi-module testing project imports the Red Hat build of Quarkus BOM of versioncom.redhat.quarkus.platform:quarkus-bom:3.2.10.-Final-redhat-00002
Migrate to the next LTS version
Let’s migrate to the next LTS version (which is 3.8.x in our case). The command is
mvn io.quarkus.platform:quarkus-maven-plugin:3.15.2:update -Dstream=3.8
When the migration process starts, the update command prints the information obtained from the registry into a console output. Here is our output:
[INFO] Looking for the newly published extensions in registry.quarkus.io [INFO] Detected project Java version: 17 [INFO] Detected project Java version: 17 [INFO] Instructions to update this project from '3.2.10.Final-redhat-00002' to '3.8.6'
As you can see in the snippet above, something appears to be wrong. Red Hat build of Quarkus is upgraded from 3.2.10.Final-redhat-00002
(product version) to 3.8.6
(community version), which is usually not intended.
We already discussed the importance of the quarkus registry for obtaining the latest version of the projects. By default, only the upstream registry is available to the CLI tool. If we need the product registry to be used as well, we need to create a config.yaml
file in the $HOME/.quarkus
directory. For more details, please follow the guide. The common registry configuration should look like:
registries:
- registry.quarkus.redhat.com
- registry.quarkus.io
With the proper registry configuration, the output is correct.
[INFO] Looking for the newly published extensions in registry.quarkus.io [INFO] Detected project Java version: 17 [INFO] Detected project Java version: 17 [INFO] Instructions to update this project from '3.2.10.Final-redhat-00002' to '3.8.6.SP2-redhat-00002'
Let’s give the tool some time to finish.
The process contains several phases:
- Initialization of the tool (fetching the latest recipes via maven and information about versions via registry).
- Application of the recipes by the OpenRewrite tooling. You can see logged messages about each change made by the recipes. For example
[WARNING] Changes have been made to customizer/src/test/java/org/apache/camel/quarkus/component/exchange/it/ExchangeLoggerCustomizer.java by:
[WARNING] io.quarkus.updates.camel.camel44.CamelQuarkusMigrationRecipe
[WARNING] org.apache.camel.upgrade.camel44.CamelMigrationRecipe
[WARNING] org.apache.camel.upgrade.camel44.CamelCoreRecipe
- Logged summary of the migration. The following screenshot shows the end of the successful migration.
Migrate to the latest LTS version (skipping a version)
Let's migrate to the latest LTS version (which is 3.15.x at this time). Our source project is based on 3.2.x. Upgrading to 3.8.x is unnecessary, the tool can directly upgrade to any newer version (3.15.x in our case). The command is
quarkus.platform:quarkus-maven-plugin:3.15.2:update
Quarkus tooling makes sure that all recipes required for the migration to stream 3.8.x and then all recipes required for the migration to stream 3.15.x are used together (in the correct order). The result of the migration is a project based on the Red Hat build of Quarkus 3.15.
[INFO] Looking for the newly published extensions in registry.quarkus.io [INFO] Detected project Java version: 17 [INFO] Detected project Java version: 17 [INFO] Instructions to update this project from '3.2.10.Final-redhat-00002' to '3.15.2.redhat-00003'
Multi module projects
Multi-module maven projects were causing problems in the past. The OpenRewrite migration tooling added a delayed execution to cover such cases. Currently, when upgrading a multi-module project, the OpenRewrite tooling postpones the migration of all child modules until the end. When the last module is being processed, all delayed migrations are executed. As a result, there’s no need for the special handling of multi-module projects.
If a problem, caused by the structure of a multi-module project appears, you can use a custom script like the following one, to force migration of each module one by one.
find . -type f -name "pom.xml" -execdir sh -c 'mvn io.quarkus.platform:quarkus-maven-plugin:3.15.2:update -N' \;
Manual validation
Let me highlight the final step of the process. It's essential to manually confirm that the project builds without errors and that all tests pass before introducing the upgraded version into production.
Here are the basic steps, which will guide you through the process.
- Verify that the migration was executed for the intended versions. (You can simply do that by checking the beginning of the console output logged by the CLI tool)
- Even though we try to cover all necessary upgrade changes by the recipes, in some cases it might not be possible. If there is a compilation error or any test fails, address the missing migration step by manually following the migration guides
(typically Camel migration guide, Camel-quarkus migration guide and Quarkus migration guide). - When the project is compilable and all tests successfully pass, migration is done. You can start using the migrated application with all benefits brought by the newer version.
Red Hat Build of Apache Camel for Spring Boot
To upgrade Red Hat Apache Camel for Spring Boot to the latest community version 4.8.0, OpenRewrite standards can be used. The recommended approaches are the following:
- Upgrade via CLI using Maven, for example:
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST,org.apache.camel.upgrade:camel-upgrade-recipes:LATEST -Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3,org.apache.camel.upgrade.camel40.CamelMigrationRecipe,org.apache.camel.upgrade.camel40.CamelMigrationRecipe,org.apache.camel.upgrade.camel44.CamelMigrationRecipe,org.apache.camel.upgrade.camel45.CamelMigrationRecipe,org.apache.camel.upgrade.camel46.CamelMigrationRecipe,org.apache.camel.upgrade.camel47.CamelMigrationRecipe
-
Configuring the OpenRewrite Maven Plugin on the project pom.xml, for example, an upgrade Maven profile could be used for this purpose:
<profiles>
<profile>
<id>upgrade</id>
<activation>
<property>
<name>upgrade</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.46.1</version>
<configuration>
<configLocation>${maven.multiModuleProjectDirectory}/rewrite.yaml</configLocation>
<exportDatatables>true</exportDatatables>
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3</recipe>
<recipe>org.apache.camel.upgrade.camel40.CamelMigrationRecipe</recipe>
<recipe>org.apache.camel.upgrade.camel44.CamelMigrationRecipe</recipe>
<recipe>org.apache.camel.upgrade.camel45.CamelMigrationRecipe</recipe>
<recipe>org.apache.camel.upgrade.camel46.CamelMigrationRecipe</recipe>
<recipe>org.apache.camel.upgrade.camel47.CamelMigrationRecipe</recipe>
<recipe>org.apache.camel.upgrade.camel48.CamelBOMMigrationRecipe</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel.upgrade</groupId>
<artifactId>camel-upgrade-recipes</artifactId>
<version>4.8.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Once the profile is added to the pom.xml, the upgrade can be executed via
mvn -Pupgrade rewrite:run
The recipes used in the previous examples are the following:
- org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3 The UpgradeSpringBoot_3_x recipe takes care of the following migrations:
- Spring Boot upgrades (2.7.x to 3.3.y, the y micro version depends on the rewrite-spring version)
- Java 17 upgrades
- javax to jakarta namespace migration
- org.apache.camel.upgrade.camel4x.CamelMigrationRecipe The
CamelMigrationRecipe
takes care of Apache Camel 4.0 to Apache Camel 4.x migration, where 4.x is the latest recipe defined in the artifactcamel-upgrade-recipes
. These recipes can be found in the Camel Upgrade Recipes repository in particular, the name of each recipe can be specified, for example, the upgrade to Camel 4.4 from Camel 3.20 is done with the recipesorg.apache.camel.upgrade.camel40.CamelMigrationRecipe
andorg.apache.camel.upgrade.camel44.CamelMigrationRecipe
.
Therefore the two approaches will migrate Apache Camel syntax and Spring Boot.
A bundled approach for Apache Camel for Spring Boot
Unlike the quarkus upgrade CLI tool, the Camel upgrade recipes do not offer all the features, especially for Camel Spring Boot, but a custom recipe can be created that will provide similar features to the Quarkus one.
For example, to upgrade from Camel 3.20.1.redhat-00109
and Spring Boot 2.7.18
, to the latest available Red Hat build of Apache Camel for Spring Boot build 4.8.0.redhat-00022 and Spring Boot 3.3.6
the following recipe.yaml
can be used:
---
type: specs.openrewrite.org/v1beta/recipe
name: org.apache.camel.upgrade.camel48.CamelSpringBootMigrationRecipe
displayName: Migrates `camel Spring Boot` application to `Camel Spring Boot 4.8`
description: Migrates `camel Spring Boot` application to `Camel Spring Boot 4.8`
recipeList:
- org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3
- org.apache.camel.upgrade.camel47.CamelMigrationRecipe
- org.apache.camel.upgrade.camel46.CamelMigrationRecipe
- org.apache.camel.upgrade.camel45.CamelMigrationRecipe
- org.apache.camel.upgrade.camel44.CamelMigrationRecipe
- org.apache.camel.upgrade.camel40.CamelMigrationRecipe
- org.openrewrite.maven.UpgradeDependencyVersion:
groupId: '*camel*'
artifactId: 'camel-spring-boot-bom'
newVersion: 4.8.0.redhat-00022
This recipe is a collection of the Spring Boot recipe and the Camel recipes discussed in the previous chapter, moreover, the UpgradeDependencyVersion
recipe will upgrade the Camel Spring Boot platform BOM references.
To use this recipe, a myRecipe.yaml
can be created in the root of a Maven project with the CamelSpringBootMigrationRecipe content and the pom.xml
profile can be updated accordingly:
<profile>
<id>upgrade</id>
<activation>
<property>
<name>upgrade</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.46.1</version>
<configuration>
<configLocation>${maven.multiModuleProjectDirectory}/myRecipe.yaml</configLocation>
<exportDatatables>true</exportDatatables>
<activeRecipes>
<recipe>org.apache.camel.upgrade.camel48.CamelSpringBootMigrationRecipe</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel.upgrade</groupId>
<artifactId>camel-upgrade-recipes</artifactId>
<version>4.8.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</profile>
Summary
You should now have a solid understanding of the CLI tools and their benefit for the migration process. While it may not make migrations effortless, it serves as an essential first step toward simplifying and streamlining the whole journey.