diff --git a/.github/workflows/alternative-os-build-main.yml b/.github/workflows/alternative-os-build-main.yml
index 170688ce45209..fc81eab36209b 100644
--- a/.github/workflows/alternative-os-build-main.yml
+++ b/.github/workflows/alternative-os-build-main.yml
@@ -41,7 +41,7 @@ jobs:
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: 'temurin'
- java-version: 17
+ java-version: 21
cache: 'maven'
- name: mvn build ${{ matrix.os }}
run: ./mvnw -B -V -D'http.keepAlive=false' -l build.log -D'maven.wagon.http.pool=false' -D'maven.wagon.httpconnectionManager.ttlSeconds=120' --no-transfer-progress -Dquickly install
diff --git a/.github/workflows/generate-sbom-main.yml b/.github/workflows/generate-sbom-main.yml
index 113d6096abab7..6b0460766395a 100644
--- a/.github/workflows/generate-sbom-main.yml
+++ b/.github/workflows/generate-sbom-main.yml
@@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- java: [ '17' ]
+ java: [ '21' ]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
diff --git a/.github/workflows/pr-build-main.yml b/.github/workflows/pr-build-main.yml
index 569680d03531d..9467f7fe951e5 100644
--- a/.github/workflows/pr-build-main.yml
+++ b/.github/workflows/pr-build-main.yml
@@ -41,11 +41,8 @@ jobs:
continue-on-error: ${{ matrix.experimental }}
strategy:
matrix:
- java: ['17']
+ java: ['21']
experimental: [ false ]
- include:
- - java: '21'
- experimental: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/pr-manual-component-test.yml b/.github/workflows/pr-manual-component-test.yml
index 1e186e1e199f0..ef88b148f140c 100644
--- a/.github/workflows/pr-manual-component-test.yml
+++ b/.github/workflows/pr-manual-component-test.yml
@@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- java: [ '17' ]
+ java: [ '21' ]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml
index 2d7bfdc3ef49e..c5fa606e36436 100644
--- a/.github/workflows/security-scan.yml
+++ b/.github/workflows/security-scan.yml
@@ -35,11 +35,11 @@ jobs:
uses: actions/checkout@v6
with:
persist-credentials: false
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: 'temurin'
- java-version: '17'
+ java-version: '21'
cache: 'maven'
- name: OWASP Dependency Check
run: ./mvnw -B -Pdependencycheck validate -DskipTests -DnvdApiKey=${{ secrets.NVD_API_KEY }} -DnvdApiDelay=5000 -l owasp-check.log
diff --git a/AGENTS.md b/AGENTS.md
index f2f3385bef390..632f852c83825 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -7,7 +7,7 @@ Guidelines for AI agents working on this codebase.
Apache Camel is an integration framework supporting routing rules in Java, XML and YAML DSLs.
- Version: 4.19.0-SNAPSHOT
-- Java: 17+ (21 for Virtual Threads)
+- Java: 21+
- Build: Maven 3.9.12+
## Structure
diff --git a/Jenkinsfile b/Jenkinsfile
index b49f2bab0cc38..bbabca5708eb0 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -49,7 +49,7 @@ pipeline {
parameters {
booleanParam(name: 'VIRTUAL_THREAD', defaultValue: false, description: 'Perform the build using virtual threads')
choice(name: 'PLATFORM_FILTER', choices: ['all', 'ppc64le', 's390x', 'ubuntu-avx'], description: 'Run on specific platform')
- choice(name: 'JDK_FILTER', choices: ['all', 'jdk_17_latest', 'jdk_21_latest', 'jdk_25_latest'], description: 'Run on specific jdk')
+ choice(name: 'JDK_FILTER', choices: ['all', 'jdk_21_latest', 'jdk_25_latest'], description: 'Run on specific jdk')
}
agent none
stages {
@@ -70,7 +70,7 @@ pipeline {
axes {
axis {
name 'JDK_NAME'
- values 'jdk_17_latest', 'jdk_21_latest', 'jdk_25_latest'
+ values 'jdk_21_latest', 'jdk_25_latest'
}
axis {
name 'PLATFORM'
@@ -78,26 +78,6 @@ pipeline {
}
}
excludes {
- exclude {
- axis {
- name 'JDK_NAME'
- values 'jdk_21_latest'
- }
- axis {
- name 'PLATFORM'
- values 'ppc64le'
- }
- }
- exclude {
- axis {
- name 'JDK_NAME'
- values 'jdk_21_latest'
- }
- axis {
- name 'PLATFORM'
- values 's390x'
- }
- }
exclude {
axis {
name 'JDK_NAME'
@@ -139,11 +119,8 @@ pipeline {
script {
if ("${PLATFORM}" == "ubuntu-avx") {
if ("${JDK_NAME}" == "jdk_21_latest") {
- // Enable virtual threads
- sh "./mvnw $MAVEN_PARAMS $MAVEN_TEST_PARAMS_UBUNTU -Darchetype.test.skip -Dmaven.test.failure.ignore=true -Dcheckstyle.skip=true install -Dcamel.threads.virtual.enabled=${params.VIRTUAL_THREAD}"
- } else if ("${JDK_NAME}" == "jdk_17_latest") {
- // Enable coverage required later by Sonar check
- sh "./mvnw $MAVEN_PARAMS $MAVEN_TEST_PARAMS -Darchetype.test.skip -Dmaven.test.failure.ignore=true -Dcheckstyle.skip=true install -Pcoverage"
+ // Enable virtual threads and coverage required later by Sonar check
+ sh "./mvnw $MAVEN_PARAMS $MAVEN_TEST_PARAMS_UBUNTU -Darchetype.test.skip -Dmaven.test.failure.ignore=true -Dcheckstyle.skip=true install -Dcamel.threads.virtual.enabled=${params.VIRTUAL_THREAD} -Pcoverage"
} else {
sh "./mvnw $MAVEN_PARAMS $MAVEN_TEST_PARAMS -Darchetype.test.skip -Dmaven.test.failure.ignore=true -Dcheckstyle.skip=true install"
}
@@ -168,7 +145,7 @@ pipeline {
script {
echo "Do Static code analysis for ${PLATFORM}-${JDK_NAME}"
// We only execute this on the main PLATFORM/JDK target
- if ("${PLATFORM}" == "ubuntu-avx" && "${JDK_NAME}" == "jdk_17_latest") {
+ if ("${PLATFORM}" == "ubuntu-avx" && "${JDK_NAME}" == "jdk_21_latest") {
withCredentials([string(credentialsId: 'apache-camel-core', variable: 'SONAR_TOKEN')]) {
echo "Code quality review ENABLED for ${PLATFORM} with ${JDK_NAME}"
sh "./mvnw $MAVEN_PARAMS -Dsonar.host.url=https://sonarcloud.io -Dsonar.java.experimental.batchModeSizeInKB=2048 -Dsonar.organization=apache -Dsonar.projectKey=apache_camel -Dsonar.branch.name=$BRANCH_NAME org.sonarsource.scanner.maven:sonar-maven-plugin:sonar"
diff --git a/Jenkinsfile.deploy b/Jenkinsfile.deploy
index 405b786d93af7..5c1db358ac001 100644
--- a/Jenkinsfile.deploy
+++ b/Jenkinsfile.deploy
@@ -15,7 +15,7 @@
* limitations under the License.
*/
def AGENT_LABEL = env.AGENT_LABEL ?: 'ubuntu'
-def JDK_NAME = env.JDK_NAME ?: 'jdk_17_latest'
+def JDK_NAME = env.JDK_NAME ?: 'jdk_21_latest'
def MAVEN_PARAMS = "-U -B -e -fae -V -Dnoassembly -Dmaven.compiler.fork=true "
diff --git a/Jenkinsfile.jbangtest b/Jenkinsfile.jbangtest
index 63729151045c7..7b0b4807f0243 100644
--- a/Jenkinsfile.jbangtest
+++ b/Jenkinsfile.jbangtest
@@ -15,7 +15,7 @@
* limitations under the License.
*/
def AGENT_LABEL = env.AGENT_LABEL ?: 'ubuntu'
-def JDK_NAME = env.JDK_NAME ?: 'jdk_17_latest'
+def JDK_NAME = env.JDK_NAME ?: 'jdk_21_latest'
def MAVEN_PARAMS = "-U -B -e -fae -V -Dnoassembly -Dmaven.compiler.fork=true "
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
index 01c0f4bbcdec2..7249ffadeb292 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
@@ -19,7 +19,7 @@
{ "name": "camel.jbang.groovyFiles", "required": false, "description": "Additional groovy source files to export to src\/main\/resources\/camel-groovy directory (Use commas to separate multiple files)", "type": "string", "javaType": "String", "secret": false },
{ "name": "camel.jbang.health", "required": false, "description": "Health check at \/observe\/health on local HTTP server (port 8080 by default)", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false, "deprecated": true },
{ "name": "camel.jbang.ignoreLoadingError", "required": false, "description": "Whether to ignore route loading and compilation errors (use this with care!)", "label": "advanced", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
- { "name": "camel.jbang.javaVersion", "required": false, "description": "Java version (17 or 21)", "type": "enum", "javaType": "String", "defaultValue": "21", "secret": false, "enum": [ "17", "21" ] },
+ { "name": "camel.jbang.javaVersion", "required": false, "description": "Java version", "type": "enum", "javaType": "String", "defaultValue": "21", "secret": false, "enum": [ "21" ] },
{ "name": "camel.jbang.jfr", "required": false, "description": "Enables Java Flight Recorder saving recording to disk on exit", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
{ "name": "camel.jbang.jfr-profile", "required": false, "description": "Java Flight Recorder profile to use (such as default or profile)", "type": "string", "javaType": "String", "defaultValue": "default", "secret": false },
{ "name": "camel.jbang.jib-maven-plugin-version", "required": false, "description": "Version to use for jib-maven-plugin if exporting to camel-main and have Kubernetes enabled (jkube.xxx options)", "label": "kubernetes", "type": "string", "javaType": "String", "defaultValue": "3.4.5", "secret": false },
diff --git a/core/camel-support/pom.xml b/core/camel-support/pom.xml
index cc010e72eb6da..9480c6c1b48bf 100644
--- a/core/camel-support/pom.xml
+++ b/core/camel-support/pom.xml
@@ -85,53 +85,4 @@
-
-
- java-21-sources
-
- [21,)
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- ${maven-compiler-plugin-version}
-
-
- default-compile
- compile
-
- compile
-
-
-
- compile-java-21
- compile
-
- compile
-
-
- 21
- ${project.basedir}/src/main/java21
- true
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
-
-
-
- true
-
-
-
-
-
-
-
-
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultThreadPoolFactory.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultThreadPoolFactory.java
index aa9c68845dab7..c69d555511b1d 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultThreadPoolFactory.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultThreadPoolFactory.java
@@ -37,6 +37,8 @@
import org.apache.camel.util.concurrent.RejectableScheduledThreadPoolExecutor;
import org.apache.camel.util.concurrent.RejectableThreadPoolExecutor;
import org.apache.camel.util.concurrent.SizedScheduledExecutorService;
+import org.apache.camel.util.concurrent.ThreadFactoryTypeAware;
+import org.apache.camel.util.concurrent.ThreadType;
/**
* Factory for thread pools that uses the JDK {@link Executors} for creating the thread pools.
@@ -57,7 +59,7 @@ public void setCamelContext(CamelContext camelContext) {
@Override
public ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
- return Executors.newCachedThreadPool(threadFactory);
+ return ThreadPoolFactoryType.from(threadFactory, Integer.MAX_VALUE).newCachedThreadPool(threadFactory);
}
@Override
@@ -79,7 +81,6 @@ public ExecutorService newThreadPool(
boolean allowCoreThreadTimeOut,
RejectedExecutionHandler rejectedExecutionHandler, ThreadFactory threadFactory)
throws IllegalArgumentException {
-
// the core pool size must be 0 or higher
if (corePoolSize < 0) {
throw new IllegalArgumentException("CorePoolSize must be >= 0, was " + corePoolSize);
@@ -90,52 +91,121 @@ public ExecutorService newThreadPool(
throw new IllegalArgumentException(
"MaxPoolSize must be >= corePoolSize, was " + maxPoolSize + " >= " + corePoolSize);
}
-
- BlockingQueue workQueue;
- if (corePoolSize == 0 && maxQueueSize <= 0) {
- // use a synchronous queue for direct-handover (no tasks stored on the queue)
- workQueue = new SynchronousQueue<>();
- // and force 1 as pool size to be able to create the thread pool by the JDK
- corePoolSize = 1;
- maxPoolSize = 1;
- } else if (maxQueueSize <= 0) {
- // use a synchronous queue for direct-handover (no tasks stored on the queue)
- workQueue = new SynchronousQueue<>();
- } else {
- // bounded task queue to store tasks on the queue
- workQueue = new LinkedBlockingQueue<>(maxQueueSize);
- }
-
- ThreadPoolExecutor answer
- = new RejectableThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue);
- answer.setThreadFactory(threadFactory);
- answer.allowCoreThreadTimeOut(allowCoreThreadTimeOut);
- if (rejectedExecutionHandler == null) {
- rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
- }
- answer.setRejectedExecutionHandler(rejectedExecutionHandler);
- return answer;
+ return ThreadPoolFactoryType.from(threadFactory, corePoolSize, maxPoolSize, maxQueueSize).newThreadPool(
+ corePoolSize, maxPoolSize, keepAliveTime, timeUnit, maxQueueSize, allowCoreThreadTimeOut,
+ rejectedExecutionHandler, threadFactory);
}
@Override
public ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory) {
- RejectedExecutionHandler rejectedExecutionHandler = profile.getRejectedExecutionHandler();
- if (rejectedExecutionHandler == null) {
- rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
+ return ThreadPoolFactoryType.from(threadFactory, profile).newScheduledThreadPool(profile, threadFactory);
+ }
+
+ private enum ThreadPoolFactoryType {
+ PLATFORM {
+ ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
+ return Executors.newCachedThreadPool(threadFactory);
+ }
+
+ ExecutorService newThreadPool(
+ int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit timeUnit, int maxQueueSize,
+ boolean allowCoreThreadTimeOut,
+ RejectedExecutionHandler rejectedExecutionHandler, ThreadFactory threadFactory)
+ throws IllegalArgumentException {
+
+ BlockingQueue workQueue;
+ if (corePoolSize == 0 && maxQueueSize <= 0) {
+ // use a synchronous queue for direct-handover (no tasks stored on the queue)
+ workQueue = new SynchronousQueue<>();
+ // and force 1 as pool size to be able to create the thread pool by the JDK
+ corePoolSize = 1;
+ maxPoolSize = 1;
+ } else if (maxQueueSize <= 0) {
+ // use a synchronous queue for direct-handover (no tasks stored on the queue)
+ workQueue = new SynchronousQueue<>();
+ } else {
+ // bounded task queue to store tasks on the queue
+ workQueue = new LinkedBlockingQueue<>(maxQueueSize);
+ }
+
+ ThreadPoolExecutor answer
+ = new RejectableThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue);
+ answer.setThreadFactory(threadFactory);
+ answer.allowCoreThreadTimeOut(allowCoreThreadTimeOut);
+ if (rejectedExecutionHandler == null) {
+ rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
+ }
+ answer.setRejectedExecutionHandler(rejectedExecutionHandler);
+ return answer;
+ }
+
+ ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory) {
+ RejectedExecutionHandler rejectedExecutionHandler = profile.getRejectedExecutionHandler();
+ if (rejectedExecutionHandler == null) {
+ rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
+ }
+
+ ScheduledThreadPoolExecutor answer
+ = new RejectableScheduledThreadPoolExecutor(
+ profile.getPoolSize(), threadFactory, rejectedExecutionHandler);
+ answer.setRemoveOnCancelPolicy(true);
+
+ // need to wrap the thread pool in a sized to guard against the problem that the
+ // JDK created thread pool has an unbounded queue (see class javadoc), which mean
+ // we could potentially keep adding tasks, and run out of memory.
+ if (profile.getMaxPoolSize() > 0) {
+ return new SizedScheduledExecutorService(answer, profile.getMaxQueueSize());
+ } else {
+ return answer;
+ }
+ }
+ },
+ VIRTUAL {
+ @Override
+ ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
+ return Executors.newThreadPerTaskExecutor(threadFactory);
+ }
+
+ @Override
+ ExecutorService newThreadPool(
+ int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit timeUnit,
+ int maxQueueSize, boolean allowCoreThreadTimeOut,
+ RejectedExecutionHandler rejectedExecutionHandler,
+ ThreadFactory threadFactory)
+ throws IllegalArgumentException {
+ return Executors.newThreadPerTaskExecutor(threadFactory);
+ }
+
+ @Override
+ ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory) {
+ return Executors.newScheduledThreadPool(0, threadFactory);
+ }
+ };
+
+ static ThreadPoolFactoryType from(ThreadFactory threadFactory, ThreadPoolProfile profile) {
+ return from(threadFactory, profile.getPoolSize(), profile.getMaxPoolSize(), profile.getMaxQueueSize());
}
- ScheduledThreadPoolExecutor answer
- = new RejectableScheduledThreadPoolExecutor(profile.getPoolSize(), threadFactory, rejectedExecutionHandler);
- answer.setRemoveOnCancelPolicy(true);
-
- // need to wrap the thread pool in a sized to guard against the problem that the
- // JDK created thread pool has an unbounded queue (see class javadoc), which mean
- // we could potentially keep adding tasks, and run out of memory.
- if (profile.getMaxPoolSize() > 0) {
- return new SizedScheduledExecutorService(answer, profile.getMaxQueueSize());
- } else {
- return answer;
+ static ThreadPoolFactoryType from(ThreadFactory threadFactory, int corePoolSize, int maxPoolSize, int maxQueueSize) {
+ return from(threadFactory, corePoolSize == 0 && maxQueueSize <= 0 ? 1 : maxPoolSize);
+ }
+
+ static ThreadPoolFactoryType from(ThreadFactory threadFactory, int maxPoolSize) {
+ if (ThreadType.current() == ThreadType.PLATFORM) {
+ return ThreadPoolFactoryType.PLATFORM;
+ }
+ return maxPoolSize > 1 && threadFactory instanceof ThreadFactoryTypeAware factoryTypeAware
+ && factoryTypeAware.isVirtual() ? ThreadPoolFactoryType.VIRTUAL : ThreadPoolFactoryType.PLATFORM;
}
- }
+ abstract ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
+
+ abstract ExecutorService newThreadPool(
+ int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit timeUnit, int maxQueueSize,
+ boolean allowCoreThreadTimeOut,
+ RejectedExecutionHandler rejectedExecutionHandler, ThreadFactory threadFactory)
+ throws IllegalArgumentException;
+
+ abstract ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory);
+ }
}
diff --git a/core/camel-support/src/main/java21/org/apache/camel/support/DefaultThreadPoolFactory.java b/core/camel-support/src/main/java21/org/apache/camel/support/DefaultThreadPoolFactory.java
deleted file mode 100644
index 8fee4c9efd828..0000000000000
--- a/core/camel-support/src/main/java21/org/apache/camel/support/DefaultThreadPoolFactory.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.support;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.RejectedExecutionHandler;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.CamelContextAware;
-import org.apache.camel.StaticService;
-import org.apache.camel.spi.ThreadPoolFactory;
-import org.apache.camel.spi.ThreadPoolProfile;
-import org.apache.camel.support.service.ServiceSupport;
-import org.apache.camel.util.concurrent.RejectableScheduledThreadPoolExecutor;
-import org.apache.camel.util.concurrent.RejectableThreadPoolExecutor;
-import org.apache.camel.util.concurrent.SizedScheduledExecutorService;
-import org.apache.camel.util.concurrent.ThreadType;
-import org.apache.camel.util.concurrent.ThreadFactoryTypeAware;
-
-/**
- * Factory for thread pools that uses the JDK {@link Executors} for creating the thread pools.
- */
-public class DefaultThreadPoolFactory extends ServiceSupport implements CamelContextAware, ThreadPoolFactory, StaticService {
-
- private CamelContext camelContext;
-
- @Override
- public CamelContext getCamelContext() {
- return camelContext;
- }
-
- @Override
- public void setCamelContext(CamelContext camelContext) {
- this.camelContext = camelContext;
- }
-
- @Override
- public ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
- return ThreadPoolFactoryType.from(threadFactory, Integer.MAX_VALUE).newCachedThreadPool(threadFactory);
- }
-
- @Override
- public ExecutorService newThreadPool(ThreadPoolProfile profile, ThreadFactory factory) {
- // allow core thread timeout is default true if not configured
- boolean allow = profile.getAllowCoreThreadTimeOut() != null ? profile.getAllowCoreThreadTimeOut() : true;
- return newThreadPool(profile.getPoolSize(),
- profile.getMaxPoolSize(),
- profile.getKeepAliveTime(),
- profile.getTimeUnit(),
- profile.getMaxQueueSize(),
- allow,
- profile.getRejectedExecutionHandler(),
- factory);
- }
-
- public ExecutorService newThreadPool(
- int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit timeUnit, int maxQueueSize,
- boolean allowCoreThreadTimeOut,
- RejectedExecutionHandler rejectedExecutionHandler, ThreadFactory threadFactory)
- throws IllegalArgumentException {
- // the core pool size must be 0 or higher
- if (corePoolSize < 0) {
- throw new IllegalArgumentException("CorePoolSize must be >= 0, was " + corePoolSize);
- }
-
- // validate max >= core
- if (maxPoolSize < corePoolSize) {
- throw new IllegalArgumentException(
- "MaxPoolSize must be >= corePoolSize, was " + maxPoolSize + " >= " + corePoolSize);
- }
- return ThreadPoolFactoryType.from(threadFactory, corePoolSize, maxPoolSize, maxQueueSize).newThreadPool(
- corePoolSize, maxPoolSize, keepAliveTime, timeUnit, maxQueueSize, allowCoreThreadTimeOut,
- rejectedExecutionHandler, threadFactory);
- }
-
- @Override
- public ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory) {
- return ThreadPoolFactoryType.from(threadFactory, profile).newScheduledThreadPool(profile, threadFactory);
- }
-
- private enum ThreadPoolFactoryType {
- PLATFORM {
- ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
- return Executors.newCachedThreadPool(threadFactory);
- }
-
- ExecutorService newThreadPool(
- int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit timeUnit, int maxQueueSize,
- boolean allowCoreThreadTimeOut,
- RejectedExecutionHandler rejectedExecutionHandler, ThreadFactory threadFactory)
- throws IllegalArgumentException {
-
- BlockingQueue workQueue;
- if (corePoolSize == 0 && maxQueueSize <= 0) {
- // use a synchronous queue for direct-handover (no tasks stored on the queue)
- workQueue = new SynchronousQueue<>();
- // and force 1 as pool size to be able to create the thread pool by the JDK
- corePoolSize = 1;
- maxPoolSize = 1;
- } else if (maxQueueSize <= 0) {
- // use a synchronous queue for direct-handover (no tasks stored on the queue)
- workQueue = new SynchronousQueue<>();
- } else {
- // bounded task queue to store tasks on the queue
- workQueue = new LinkedBlockingQueue<>(maxQueueSize);
- }
-
- ThreadPoolExecutor answer
- = new RejectableThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue);
- answer.setThreadFactory(threadFactory);
- answer.allowCoreThreadTimeOut(allowCoreThreadTimeOut);
- if (rejectedExecutionHandler == null) {
- rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
- }
- answer.setRejectedExecutionHandler(rejectedExecutionHandler);
- return answer;
- }
-
- ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory) {
- RejectedExecutionHandler rejectedExecutionHandler = profile.getRejectedExecutionHandler();
- if (rejectedExecutionHandler == null) {
- rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
- }
-
- ScheduledThreadPoolExecutor answer
- = new RejectableScheduledThreadPoolExecutor(profile.getPoolSize(), threadFactory, rejectedExecutionHandler);
- answer.setRemoveOnCancelPolicy(true);
-
- // need to wrap the thread pool in a sized to guard against the problem that the
- // JDK created thread pool has an unbounded queue (see class javadoc), which mean
- // we could potentially keep adding tasks, and run out of memory.
- if (profile.getMaxPoolSize() > 0) {
- return new SizedScheduledExecutorService(answer, profile.getMaxQueueSize());
- } else {
- return answer;
- }
- }
- },
- VIRTUAL {
- @Override
- ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
- return Executors.newThreadPerTaskExecutor(threadFactory);
- }
-
- @Override
- ExecutorService newThreadPool(int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit timeUnit,
- int maxQueueSize, boolean allowCoreThreadTimeOut,
- RejectedExecutionHandler rejectedExecutionHandler,
- ThreadFactory threadFactory) throws IllegalArgumentException {
- return Executors.newThreadPerTaskExecutor(threadFactory);
- }
-
- @Override
- ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory) {
- return Executors.newScheduledThreadPool(0, threadFactory);
- }
- };
-
- static ThreadPoolFactoryType from(ThreadFactory threadFactory, ThreadPoolProfile profile) {
- return from(threadFactory, profile.getPoolSize(), profile.getMaxPoolSize(), profile.getMaxQueueSize());
- }
-
- static ThreadPoolFactoryType from(ThreadFactory threadFactory, int corePoolSize, int maxPoolSize, int maxQueueSize) {
- return from(threadFactory, corePoolSize == 0 && maxQueueSize <= 0 ? 1 : maxPoolSize);
- }
-
- static ThreadPoolFactoryType from(ThreadFactory threadFactory, int maxPoolSize) {
- if (ThreadType.current() == ThreadType.PLATFORM) {
- return ThreadPoolFactoryType.PLATFORM;
- }
- return maxPoolSize > 1 && threadFactory instanceof ThreadFactoryTypeAware factoryTypeAware && factoryTypeAware.isVirtual() ?
- ThreadPoolFactoryType.VIRTUAL : ThreadPoolFactoryType.PLATFORM;
- }
-
- abstract ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
-
- abstract ExecutorService newThreadPool(
- int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit timeUnit, int maxQueueSize,
- boolean allowCoreThreadTimeOut,
- RejectedExecutionHandler rejectedExecutionHandler, ThreadFactory threadFactory)
- throws IllegalArgumentException;
-
- abstract ScheduledExecutorService newScheduledThreadPool(ThreadPoolProfile profile, ThreadFactory threadFactory);
- }
-}
diff --git a/core/camel-util/pom.xml b/core/camel-util/pom.xml
index 1f5d4115a181c..242635ad773f2 100644
--- a/core/camel-util/pom.xml
+++ b/core/camel-util/pom.xml
@@ -272,52 +272,5 @@
-
- java-21-sources
-
- [21,)
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- ${maven-compiler-plugin-version}
-
-
- default-compile
- compile
-
- compile
-
-
-
- compile-java-21
- compile
-
- compile
-
-
- 21
- ${project.basedir}/src/main/java21
- true
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
-
-
-
- true
-
-
-
-
-
-
-
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/concurrent/CamelThreadFactory.java b/core/camel-util/src/main/java/org/apache/camel/util/concurrent/CamelThreadFactory.java
index 570e02796c09d..9c179c7ba1981 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/concurrent/CamelThreadFactory.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/concurrent/CamelThreadFactory.java
@@ -16,32 +16,40 @@
*/
package org.apache.camel.util.concurrent;
-import java.util.concurrent.ThreadFactory;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Thread factory which creates threads supporting a naming pattern.
+ * Thread factory which creates threads supporting a naming pattern. The factory creates virtual threads in case the
+ * System property {@code camel.threads.virtual.enabled} set to {@code true}.
*/
-public final class CamelThreadFactory implements ThreadFactory {
+public final class CamelThreadFactory implements ThreadFactoryTypeAware {
private static final Logger LOG = LoggerFactory.getLogger(CamelThreadFactory.class);
+ private static final ThreadFactoryType TYPE = ThreadFactoryType.current();
+
private final String pattern;
private final String name;
private final boolean daemon;
+ private final ThreadFactoryType threadType;
public CamelThreadFactory(String pattern, String name, boolean daemon) {
this.pattern = pattern;
this.name = name;
this.daemon = daemon;
+ this.threadType = daemon ? TYPE : ThreadFactoryType.PLATFORM;
+ }
+
+ @Override
+ public boolean isVirtual() {
+ return threadType == ThreadFactoryType.VIRTUAL;
}
@Override
public Thread newThread(Runnable runnable) {
String threadName = ThreadHelper.resolveThreadName(pattern, name);
- Thread answer = new Thread(runnable, threadName);
- answer.setDaemon(daemon);
+
+ Thread answer = threadType.newThread(threadName, daemon, runnable);
LOG.trace("Created thread[{}] -> {}", threadName, answer);
return answer;
@@ -55,4 +63,27 @@ public String getName() {
public String toString() {
return "CamelThreadFactory[" + name + "]";
}
+
+ private enum ThreadFactoryType {
+ PLATFORM {
+ Thread.Builder newThreadBuilder(String threadName, boolean daemon) {
+ return Thread.ofPlatform().name(threadName).daemon(daemon);
+ }
+ },
+ VIRTUAL {
+ Thread.Builder newThreadBuilder(String threadName, boolean daemon) {
+ return Thread.ofVirtual().name(threadName);
+ }
+ };
+
+ Thread newThread(String threadName, boolean daemon, Runnable runnable) {
+ return newThreadBuilder(threadName, daemon).unstarted(runnable);
+ }
+
+ abstract Thread.Builder newThreadBuilder(String threadName, boolean daemon);
+
+ static ThreadFactoryType current() {
+ return ThreadType.current() == ThreadType.VIRTUAL ? VIRTUAL : PLATFORM;
+ }
+ }
}
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/concurrent/ThreadType.java b/core/camel-util/src/main/java/org/apache/camel/util/concurrent/ThreadType.java
index b048a2640c9c0..c43926be2df67 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/concurrent/ThreadType.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/concurrent/ThreadType.java
@@ -16,15 +16,29 @@
*/
package org.apache.camel.util.concurrent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
- * Defines the existing type of threads. The virtual threads can only be used with JDK 21+ and the system property
- * {@code camel.threads.virtual.enabled} set to {@code true}.
+ * Defines the existing type of threads. The virtual threads can only be used with the system property
+ * {@code camel.threads.virtual.enabled} set to {@code true}. The default value is {@code false} which means that
+ * platform threads are used by default.
*/
public enum ThreadType {
PLATFORM,
VIRTUAL;
+ private static final Logger LOG = LoggerFactory.getLogger(ThreadType.class);
+ private static final ThreadType CURRENT = Boolean.getBoolean("camel.threads.virtual.enabled") ? VIRTUAL : PLATFORM;
+ static {
+ if (CURRENT == VIRTUAL) {
+ LOG.info("The type of thread detected is: {}", CURRENT);
+ } else {
+ LOG.debug("The type of thread detected is: {}", CURRENT);
+ }
+ }
+
public static ThreadType current() {
- return PLATFORM;
+ return CURRENT;
}
}
diff --git a/core/camel-util/src/main/java21/org/apache/camel/util/concurrent/CamelThreadFactory.java b/core/camel-util/src/main/java21/org/apache/camel/util/concurrent/CamelThreadFactory.java
deleted file mode 100644
index d6c54ddc692ad..0000000000000
--- a/core/camel-util/src/main/java21/org/apache/camel/util/concurrent/CamelThreadFactory.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.util.concurrent;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Thread factory which creates threads supporting a naming pattern.
- * The factory creates virtual threads in case the System property {@code camel.threads.virtual.enabled} set to
- * {@code true}.
- */
-public final class CamelThreadFactory implements ThreadFactoryTypeAware {
- private static final Logger LOG = LoggerFactory.getLogger(CamelThreadFactory.class);
-
- private static final ThreadFactoryType TYPE = ThreadFactoryType.current();
-
- private final String pattern;
- private final String name;
- private final boolean daemon;
- private final ThreadFactoryType threadType;
-
- public CamelThreadFactory(String pattern, String name, boolean daemon) {
- this.pattern = pattern;
- this.name = name;
- this.daemon = daemon;
- this.threadType = daemon ? TYPE : ThreadFactoryType.PLATFORM;
- }
-
- @Override
- public boolean isVirtual() {
- return threadType == ThreadFactoryType.VIRTUAL;
- }
-
- @Override
- public Thread newThread(Runnable runnable) {
- String threadName = ThreadHelper.resolveThreadName(pattern, name);
-
- Thread answer = threadType.newThread(threadName, daemon, runnable);
-
- LOG.trace("Created thread[{}] -> {}", threadName, answer);
- return answer;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public String toString() {
- return "CamelThreadFactory[" + name + "]";
- }
-
- private enum ThreadFactoryType {
- PLATFORM {
- Thread.Builder newThreadBuilder(String threadName, boolean daemon) {
- return Thread.ofPlatform().name(threadName).daemon(daemon);
- }
- },
- VIRTUAL {
- Thread.Builder newThreadBuilder(String threadName, boolean daemon) {
- return Thread.ofVirtual().name(threadName);
- }
- };
-
- Thread newThread(String threadName, boolean daemon, Runnable runnable) {
- return newThreadBuilder(threadName, daemon).unstarted(runnable);
- }
-
- abstract Thread.Builder newThreadBuilder(String threadName, boolean daemon);
-
- static ThreadFactoryType current() {
- return ThreadType.current() == ThreadType.VIRTUAL ? VIRTUAL : PLATFORM;
- }
- }
-}
-
diff --git a/core/camel-util/src/main/java21/org/apache/camel/util/concurrent/ThreadType.java b/core/camel-util/src/main/java21/org/apache/camel/util/concurrent/ThreadType.java
deleted file mode 100644
index 16a9401371d24..0000000000000
--- a/core/camel-util/src/main/java21/org/apache/camel/util/concurrent/ThreadType.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.util.concurrent;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Defines the existing type of threads. The virtual threads can only be used with JDK 21+ and the system property
- * {@code camel.threads.virtual.enabled} set to {@code true}.
- * The default value is {@code false} which means that platform threads are used by default.
- */
-public enum ThreadType {
- PLATFORM,
- VIRTUAL;
- private static final Logger LOG = LoggerFactory.getLogger(ThreadType.class);
- private static final ThreadType CURRENT = Boolean.getBoolean("camel.threads.virtual.enabled") ? VIRTUAL : PLATFORM;
- static {
- if (CURRENT == VIRTUAL) {
- LOG.info("The type of thread detected is: {}", CURRENT);
- } else {
- LOG.debug("The type of thread detected is: {}", CURRENT);
- }
- }
- public static ThreadType current() {
- return CURRENT;
- }
-}
diff --git a/docs/main/modules/contributing/pages/building.adoc b/docs/main/modules/contributing/pages/building.adoc
index 1a15528e90591..af94197333021 100644
--- a/docs/main/modules/contributing/pages/building.adoc
+++ b/docs/main/modules/contributing/pages/building.adoc
@@ -18,7 +18,7 @@
== Prerequisites for Camel 4.x
-* Java 17 (we test using https://adoptium.net/[OpenJDK], but any modern JDK should be fine).
+* Java 21 (we test using https://adoptium.net/[OpenJDK], but any modern JDK should be fine).
* https://github.com/takari/maven-wrapper[Maven Wrapper] can be used and is bundled.
@@ -33,7 +33,7 @@ Running the Maven Wrapper `mvnw` script with `-v` parameter from the root direct
./mvnw -v
Apache Maven 1.2.3
Maven home: /home/user/.m2/wrapper/dists/apache-maven-1.2.3-bin/deadbeef/apache-maven-1.2.3
-Java version: 17.0.5, vendor: Eclipse Adoptium, runtime: /home/user/java/17.0.5-tem
+Java version: 21.0.10, vendor: Eclipse Adoptium, runtime: /home/user/java/21.0.10-tem
Default locale: en_IE, platform encoding: UTF-8
OS name: "linux", version: "6.3.7-200.fc38.x86_64", arch: "amd64", family: "unix"
----
diff --git a/docs/main/modules/contributing/pages/index.adoc b/docs/main/modules/contributing/pages/index.adoc
index 9df2eabad0c55..246d385b6b33d 100644
--- a/docs/main/modules/contributing/pages/index.adoc
+++ b/docs/main/modules/contributing/pages/index.adoc
@@ -127,7 +127,7 @@ If you are an Apache Camel committer, then you may also clone the https://gitbox
To build the project, you need http://maven.apache.org/download.html[Apache Maven].
-- To build Camel 4, you need Java 17 Apache Maven version 3.9.6 or higher.
+- To build Camel 4, you need Java 21 and Apache Maven version 3.9.6 or higher.
=== Building Camel 4
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index f8337ba604803..875d9b496b110 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -4153,7 +4153,7 @@ The camel.jbang supports 45 options, which are listed below.
| *camel.jbang.groovyFiles* | Additional groovy source files to export to src/main/resources/camel-groovy directory (Use commas to separate multiple files) | | String
| *camel.jbang.health* | Health check at /observe/health on local HTTP server (port 8080 by default) | false | boolean
| *camel.jbang.ignoreLoadingError* | Whether to ignore route loading and compilation errors (use this with care!) | false | boolean
-| *camel.jbang.javaVersion* | Java version (17 or 21) | 21 | String
+| *camel.jbang.javaVersion* | Java version | 21 | String
| *camel.jbang.jfr* | Enables Java Flight Recorder saving recording to disk on exit | false | boolean
| *camel.jbang.jfr-profile* | Java Flight Recorder profile to use (such as default or profile) | default | String
| *camel.jbang.jib-maven-plugin-version* | Version to use for jib-maven-plugin if exporting to camel-main and have Kubernetes enabled (jkube.xxx options) | 3.4.5 | String
diff --git a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
index 01c0f4bbcdec2..7249ffadeb292 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
+++ b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
@@ -19,7 +19,7 @@
{ "name": "camel.jbang.groovyFiles", "required": false, "description": "Additional groovy source files to export to src\/main\/resources\/camel-groovy directory (Use commas to separate multiple files)", "type": "string", "javaType": "String", "secret": false },
{ "name": "camel.jbang.health", "required": false, "description": "Health check at \/observe\/health on local HTTP server (port 8080 by default)", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false, "deprecated": true },
{ "name": "camel.jbang.ignoreLoadingError", "required": false, "description": "Whether to ignore route loading and compilation errors (use this with care!)", "label": "advanced", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
- { "name": "camel.jbang.javaVersion", "required": false, "description": "Java version (17 or 21)", "type": "enum", "javaType": "String", "defaultValue": "21", "secret": false, "enum": [ "17", "21" ] },
+ { "name": "camel.jbang.javaVersion", "required": false, "description": "Java version", "type": "enum", "javaType": "String", "defaultValue": "21", "secret": false, "enum": [ "21" ] },
{ "name": "camel.jbang.jfr", "required": false, "description": "Enables Java Flight Recorder saving recording to disk on exit", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
{ "name": "camel.jbang.jfr-profile", "required": false, "description": "Java Flight Recorder profile to use (such as default or profile)", "type": "string", "javaType": "String", "defaultValue": "default", "secret": false },
{ "name": "camel.jbang.jib-maven-plugin-version", "required": false, "description": "Version to use for jib-maven-plugin if exporting to camel-main and have Kubernetes enabled (jkube.xxx options)", "label": "kubernetes", "type": "string", "javaType": "String", "defaultValue": "3.4.5", "secret": false },
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
index 7ac476c14e9b9..8b63fe340bc68 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
@@ -368,10 +368,8 @@ protected void copyDockerFiles(String buildDir) throws Exception {
Path docker = Path.of(buildDir).resolve("src/main/docker");
Files.createDirectories(docker);
String[] ids = gav.split(":");
- // we only support and have docker files for java 17 or 21
- String v = javaVersion.equals("17") ? "17" : "21";
InputStream is
- = ExportCamelMain.class.getClassLoader().getResourceAsStream("templates/Dockerfile" + v + ".tmpl");
+ = ExportCamelMain.class.getClassLoader().getResourceAsStream("templates/Dockerfile21.tmpl");
String context = IOHelper.loadText(is);
IOHelper.close(is);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
index 435119ffe579e..81f5970955c76 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
@@ -64,8 +64,8 @@ public final class CamelJBangConstants {
javaType = "String")
public static final String GAV = "camel.jbang.gav";
- @Metadata(description = "Java version (17 or 21)",
- javaType = "String", enums = "17,21", defaultValue = "21")
+ @Metadata(description = "Java version",
+ javaType = "String", enums = "21", defaultValue = "21")
public static final String JAVA_VERSION = "camel.jbang.javaVersion";
@Metadata(description = "Apache Camel Kamelets version. By default the Kamelets are the same version as Camel.",
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile17.tmpl b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile17.tmpl
deleted file mode 100644
index c57a8c7abdc10..0000000000000
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile17.tmpl
+++ /dev/null
@@ -1,97 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-####
-# This Dockerfile is used in order to build a container that runs the Camel application
-#
-# ./mvnw clean package
-# docker build -f src/main/docker/Dockerfile -t {{ .ArtifactId }}:{{ .Version }} .
-# docker run -it {{ .ArtifactId }}:{{ .Version }}
-#
-# This image uses the `run-java.sh` script to run the application.
-# This scripts computes the command line to execute your Java application, and
-# includes memory/GC tuning.
-# You can configure the behavior using the following environment properties:
-# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
-# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
-# in JAVA_OPTS (example: "-Dsome.property=foo")
-# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
-# used to calculate a default maximal heap memory based on a containers restriction.
-# If used in a container without any memory constraints for the container then this
-# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
-# of the container available memory as set here. The default is `50` which means 50%
-# of the available memory is used as an upper boundary. You can skip this mechanism by
-# setting this value to `0` in which case no `-Xmx` option is added.
-# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
-# is used to calculate a default initial heap memory based on the maximum heap memory.
-# If used in a container without any memory constraints for the container then this
-# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
-# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
-# is used as the initial heap size. You can skip this mechanism by setting this value
-# to `0` in which case no `-Xms` option is added (example: "25")
-# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
-# This is used to calculate the maximum value of the initial heap memory. If used in
-# a container without any memory constraints for the container then this option has
-# no effect. If there is a memory constraint then `-Xms` is limited to the value set
-# here. The default is 4096MB which means the calculated value of `-Xms` never will
-# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
-# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
-# when things are happening. This option, if set to true, will set
-# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
-# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
-# true").
-# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
-# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
-# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
-# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
-# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
-# (example: "20")
-# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
-# (example: "40")
-# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
-# (example: "4")
-# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
-# previous GC times. (example: "90")
-# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
-# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
-# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
-# contain the necessary JRE command-line options to specify the required GC, which
-# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
-# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
-# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
-# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
-# accessed directly. (example: "foo.example.com,bar.example.com")
-#
-# If you want to include the debug port into your docker image
-# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
-# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
-# when running the container
-#
-###
-FROM registry.access.redhat.com/ubi8/openjdk-17:1.23
-
-COPY --chown=185 target/{{ .AppJar }} /deployments/
-
-# Uncomment to expose any given port
-# EXPOSE 8080
-USER 185
-# Uncomment to provide any Java option
-# ENV JAVA_OPTS=""
-ENV JAVA_APP_JAR="/deployments/{{ .AppJar }}"
-
-ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
-
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java
index 8039058119dd5..26e025f61cb67 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java
@@ -61,14 +61,14 @@ private static Stream runtimeProvider() {
@ParameterizedTest
@MethodSource("runtimeProvider")
- public void shouldGenerateJava17(RuntimeType rt) throws Exception {
+ public void shouldGenerateExplicitJava21(RuntimeType rt) throws Exception {
// prepare as we need application.properties that contains jib settings
Files.copy(new File("src/test/resources/application-jib.properties").toPath(), profile.toPath(),
StandardCopyOption.REPLACE_EXISTING);
Export command = new Export(new CamelJBangMain());
CommandLine.populateCommand(command, "--gav=examples:route:1.0.0", "--dir=" + workingDir,
- "--runtime=%s".formatted(rt.runtime()), "--java-version=17", "target/test-classes/route.yaml");
+ "--runtime=%s".formatted(rt.runtime()), "--java-version=21", "target/test-classes/route.yaml");
int exit = command.doCall();
Assertions.assertEquals(0, exit);
@@ -76,9 +76,9 @@ public void shouldGenerateJava17(RuntimeType rt) throws Exception {
Assertions.assertEquals("examples", model.getGroupId());
Assertions.assertEquals("route", model.getArtifactId());
Assertions.assertEquals("1.0.0", model.getVersion());
- Assertions.assertEquals("17", model.getProperties().getProperty("java.version"));
+ Assertions.assertEquals("21", model.getProperties().getProperty("java.version"));
Assertions.assertEquals("abc", model.getProperties().getProperty("jib.label"));
- Assertions.assertEquals("mirror.gcr.io/library/eclipse-temurin:17-jre",
+ Assertions.assertEquals("mirror.gcr.io/library/eclipse-temurin:21-jre",
model.getProperties().getProperty("jib.from.image"));
// should contain jib plugin
diff --git a/dsl/camel-jbang/camel-jbang-main/dist/CamelJBang.java b/dsl/camel-jbang/camel-jbang-main/dist/CamelJBang.java
index d47edb0f71406..57a7fd7f673d0 100755
--- a/dsl/camel-jbang/camel-jbang-main/dist/CamelJBang.java
+++ b/dsl/camel-jbang/camel-jbang-main/dist/CamelJBang.java
@@ -17,7 +17,7 @@
* limitations under the License.
*/
-//JAVA 17+
+//JAVA 21+
//REPOS central=https://repo1.maven.org/maven2,apache-snapshot=https://repository.apache.org/content/groups/snapshots/
//DEPS org.apache.camel:camel-bom:${camel.jbang.version:4.18.0}@pom
//DEPS org.apache.camel:camel-jbang-core:${camel.jbang.version:4.18.0}
diff --git a/dsl/camel-jbang/camel-jbang-main/src/main/jbang/main/CamelJBang.java b/dsl/camel-jbang/camel-jbang-main/src/main/jbang/main/CamelJBang.java
index d47edb0f71406..57a7fd7f673d0 100755
--- a/dsl/camel-jbang/camel-jbang-main/src/main/jbang/main/CamelJBang.java
+++ b/dsl/camel-jbang/camel-jbang-main/src/main/jbang/main/CamelJBang.java
@@ -17,7 +17,7 @@
* limitations under the License.
*/
-//JAVA 17+
+//JAVA 21+
//REPOS central=https://repo1.maven.org/maven2,apache-snapshot=https://repository.apache.org/content/groups/snapshots/
//DEPS org.apache.camel:camel-bom:${camel.jbang.version:4.18.0}@pom
//DEPS org.apache.camel:camel-jbang-core:${camel.jbang.version:4.18.0}
diff --git a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
index 24654dd5f4c0a..f62bc97157e2d 100644
--- a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
+++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
@@ -128,11 +128,25 @@ public CompatibilityResult camel_migration_compatibility(
if (javaVersion != null && !javaVersion.isBlank()) {
int javaVer = parseJavaVersion(javaVersion);
boolean javaCompatible = true;
- String requiredVersion = "17";
-
- if (targetMajor >= 4 && javaVer < 17) {
- javaCompatible = false;
- blockers.add("Camel 4.x requires Java 17+. Current Java version is " + javaVersion + ".");
+ String requiredVersion;
+
+ if (targetMajor >= 4) {
+ int targetMinor = parseMinorVersion(targetVersion);
+ if (targetMajor > 4 || targetMinor >= 19) {
+ requiredVersion = "21";
+ if (javaVer < 21) {
+ javaCompatible = false;
+ blockers.add("Camel 4.19+ requires Java 21+. Current Java version is " + javaVersion + ".");
+ }
+ } else {
+ requiredVersion = "17";
+ if (javaVer < 17) {
+ javaCompatible = false;
+ blockers.add("Camel 4.x requires Java 17+. Current Java version is " + javaVersion + ".");
+ }
+ }
+ } else {
+ requiredVersion = "11";
}
javaCompat = new JavaCompatibility(javaVersion, requiredVersion, javaCompatible);
@@ -247,13 +261,9 @@ public MigrationRecipesResult camel_migration_recipes(
List javaUpgradeSuggestions = new ArrayList<>();
if (javaVersion != null && !javaVersion.isBlank()) {
int javaVer = parseJavaVersion(javaVersion);
- if (javaVer < 17) {
+ if (javaVer < 21) {
javaUpgradeSuggestions.add(
- "Consider upgrading to Java 17. "
- + "OpenRewrite recipe: org.openrewrite.java.migrate.UpgradeToJava17");
- } else if (javaVer < 21) {
- javaUpgradeSuggestions.add(
- "Consider upgrading to Java 21 for virtual threads support. "
+ "Camel 4.19+ requires Java 21+. "
+ "OpenRewrite recipe: org.openrewrite.java.migrate.UpgradeToJava21");
}
}
@@ -325,6 +335,21 @@ private int parseMajorVersion(String version) {
}
}
+ private int parseMinorVersion(String version) {
+ if (version == null) {
+ return 0;
+ }
+ try {
+ String[] parts = version.split("\\.");
+ if (parts.length >= 2) {
+ return Integer.parseInt(parts[1]);
+ }
+ return 0;
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
private int parseJavaVersion(String version) {
if (version == null) {
return 0;
diff --git a/pom.xml b/pom.xml
index 61815c06f3c16..70736b0783b10 100644
--- a/pom.xml
+++ b/pom.xml
@@ -110,7 +110,7 @@
UTF-8
scpexe://people.apache.org/www/camel.apache.org/maven/
- 17
+ 21
${jdk.version}
${jdk.version}
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/customized-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/customized-v3/pom.xml
index eb7375e01afeb..4988dbca8a882 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/customized-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/customized-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/expanded-v3-yaml/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/expanded-v3-yaml/pom.xml
index 78fd49ec4d51a..bb549c5814ade 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/expanded-v3-yaml/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/expanded-v3-yaml/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-dto-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-dto-v3/pom.xml
index 621468eecf14f..7c248f8d3742f 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-dto-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-dto-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3-yaml/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3-yaml/pom.xml
index 308765b9d7b80..a02c2f5a541c6 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3-yaml/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3-yaml/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3/pom.xml
index 70cef1e80c53c..25db335cca8f0 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-dto-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-dto-v3/pom.xml
index 9e98a3d9a4563..d27608d2110a8 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-dto-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-dto-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-v3/pom.xml
index 0340e50214942..5a7326b23674c 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-xml-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-dto-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-dto-v3/pom.xml
index 559095996dac1..6cfc2c233e113 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-dto-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-dto-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-kamelet-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-kamelet-v3/pom.xml
index 7526d4e050b7e..703d59d902b44 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-kamelet-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-kamelet-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21
diff --git a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-v3/pom.xml b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-v3/pom.xml
index c0932b98d0d59..2b4d48d9abc56 100644
--- a/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-v3/pom.xml
+++ b/tooling/maven/camel-restdsl-openapi-plugin/src/it/simple-yaml-v3/pom.xml
@@ -29,9 +29,9 @@
UTF-8
- 17
- 17
- 17
+ 21
+ 21
+ 21