From b43b882c67587618d4c8e3ee19a9a671e46bc5ab Mon Sep 17 00:00:00 2001 From: Jean-Louis Monteiro Date: Wed, 14 Jan 2026 10:18:13 +0100 Subject: [PATCH 01/10] Bind to an ephemeral port instead to avoid conflicts --- .../failover/FailoverDurableSubTransactionTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverDurableSubTransactionTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverDurableSubTransactionTest.java index ad4db46912..f4a4d2a2f9 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverDurableSubTransactionTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverDurableSubTransactionTest.java @@ -182,6 +182,9 @@ public void postProcessDispatch(MessageDispatch messageDispatch) { // Get the actual bound URI after broker starts (important for ephemeral ports) url = broker.getTransportConnectors().get(0).getPublishableConnectString(); + // Get the actual bound URI after broker starts (important for ephemeral ports) + url = broker.getTransportConnectors().get(0).getPublishableConnectString(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); cf.setAlwaysSyncSend(true); cf.setAlwaysSessionAsync(false); @@ -290,6 +293,9 @@ public void acknowledge(ConsumerBrokerExchange consumerExchange, MessageAck ack) // Get the actual bound URI after broker starts (important for ephemeral ports) url = broker.getTransportConnectors().get(0).getPublishableConnectString(); + // Get the actual bound URI after broker starts (important for ephemeral ports) + url = broker.getTransportConnectors().get(0).getPublishableConnectString(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); cf.setAlwaysSyncSend(true); cf.setAlwaysSessionAsync(true); From e0d9c412fc2c87458297884357ea1a580d026236 Mon Sep 17 00:00:00 2001 From: Matt Pavlovich Date: Thu, 13 Nov 2025 09:57:32 -0600 Subject: [PATCH 02/10] [#] NO-JIRA: Update Jenkinsfile to add JDK 25 --- Jenkinsfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 95fb388301..9338b7e46c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -46,8 +46,8 @@ pipeline { } parameters { - choice(name: 'nodeLabel', choices: [ 'ubuntu', 's390x', 'arm', 'Windows' ]) - choice(name: 'jdkVersion', choices: ['jdk_17_latest', 'jdk_21_latest', 'jdk_24_latest', 'jdk_17_latest_windows', 'jdk_21_latest_windows', 'jdk_24_latest_windows']) + choice(name: 'nodeLabel', choices: [ 'ubuntu', 's390x', 'arm', 'Windows' ]) + choice(name: 'jdkVersion', choices: ['jdk_17_latest', 'jdk_21_latest', 'jdk_25_latest', 'jdk_17_latest_windows', 'jdk_21_latest_windows', 'jdk_25_latest_windows']) booleanParam(name: 'deployEnabled', defaultValue: false) booleanParam(name: 'parallelTestsEnabled', defaultValue: true) booleanParam(name: 'sonarEnabled', defaultValue: false) @@ -77,12 +77,12 @@ pipeline { } } - stage('Build JDK 24') { + stage('Build JDK 25') { tools { - jdk "jdk_24_latest" + jdk "jdk_25_latest" } steps { - echo 'Building JDK 24' + echo 'Building JDK 25' sh 'java -version' sh 'mvn -version' sh 'mvn -U -B -e clean install -DskipTests' From c8261e8e8b10251b52940cc86d834e661bdf63fd Mon Sep 17 00:00:00 2001 From: Matt Pavlovich Date: Fri, 14 Nov 2025 15:07:05 -0600 Subject: [PATCH 03/10] [AMQ-9563] Add a SubjectShim to support JAAS API JDK 24+ --- activemq-broker/pom.xml | 29 ++++++++++++++- .../activemq/broker/jmx/AnnotatedMBean.java | 11 ++++-- .../activemq/broker/jmx/SubjectShim.java | 35 +++++++++++++++++++ .../activemq/broker/jmx/SubjectShim.java | 35 +++++++++++++++++++ 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 activemq-broker/src/main/java/org/apache/activemq/broker/jmx/SubjectShim.java create mode 100644 activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java diff --git a/activemq-broker/pom.xml b/activemq-broker/pom.xml index 5ded615389..15326983ce 100644 --- a/activemq-broker/pom.xml +++ b/activemq-broker/pom.xml @@ -242,7 +242,7 @@ - + activemq.tests-autoTransport @@ -263,5 +263,32 @@ + + jdk24-plus + + [24,) + + + + + maven-compiler-plugin + + + java24-compile + compile + + compile + + + 24 + ${project.basedir}/src/main/java24 + true + + + + + + + diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java index 51c135ddf5..7dcfd33c64 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java +++ b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java @@ -205,8 +205,15 @@ public Object invoke(String s, Object[] objects, String[] strings) throws MBeanE objects = (objects == null) ? new Object[]{} : objects; JMXAuditLogEntry entry = null; if (audit != OFF) { - // [AMQ-9563] TODO: JDK 21 use Subject.current() instead - Subject subject = Subject.getSubject(AccessController.getContext()); + /** + * [AMQ-9563] JDK JAAS API conversion assistance + * + * Use a shim along with multi-release jar to + * support JDK 17 and JDK 24+ in one build. + * + * see: src/main/java24 folder + */ + Subject subject = SubjectShim.lookupSubject(); String caller = "anonymous"; if (subject != null) { caller = ""; diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/SubjectShim.java b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/SubjectShim.java new file mode 100644 index 0000000000..fb8862ea37 --- /dev/null +++ b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/SubjectShim.java @@ -0,0 +1,35 @@ +/** + * 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.activemq.broker.jmx; + +import javax.security.auth.Subject; +import java.security.AccessController; + +/** + * [AMQ-9563] JDK JAAS API conversion assistance + * + * This instance of the class is for JDK [17, 24) + * + */ +public class SubjectShim { + + private SubjectShim() {} + + public static Subject lookupSubject() { + return Subject.getSubject(AccessController.getContext()); + } +} diff --git a/activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java b/activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java new file mode 100644 index 0000000000..d90728014f --- /dev/null +++ b/activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java @@ -0,0 +1,35 @@ +/** + * 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.activemq.broker.jmx; + +import javax.security.auth.Subject; +import java.security.AccessController; + +/** + * [AMQ-9563] JDK JAAS API conversion assistance + * + * This instance of the class is for JDK 24+ + * + */ +public class SubjectShim { + + private SubjectShim() {} + + public static Subject lookupSubject() { + return Subject.current(); + } +} From 184c64c527198a60559e0e0f2a121973c8cf6ee1 Mon Sep 17 00:00:00 2001 From: Matt Pavlovich Date: Fri, 14 Nov 2025 15:35:48 -0600 Subject: [PATCH 04/10] [AMQ-9366] Add DataFileFactroy to KahaDBPersistenceAdapter and update test to remove SecurityManager Co-authored-by: Gurpartap Singh --- .../kahadb/KahaDBPersistenceAdapter.java | 5 ++ .../store/kahadb/MessageDatabase.java | 17 +++++-- .../kahadb/disk/journal/DataFileFactory.java | 23 +++++++++ .../disk/journal/DefaultDataFileFactory.java | 27 +++++++++++ .../store/kahadb/disk/journal/Journal.java | 15 ++++-- .../store/kahadb/JournalArchiveTest.java | 17 +++---- .../disk/journal/ErrorDataFileFactory.java | 47 +++++++++++++++++++ 7 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DataFileFactory.java create mode 100644 activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DefaultDataFileFactory.java create mode 100644 activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/journal/ErrorDataFileFactory.java diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/KahaDBPersistenceAdapter.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/KahaDBPersistenceAdapter.java index eb0d56d154..1955f8450b 100644 --- a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/KahaDBPersistenceAdapter.java +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/KahaDBPersistenceAdapter.java @@ -44,6 +44,7 @@ import org.apache.activemq.store.kahadb.data.KahaLocalTransactionId; import org.apache.activemq.store.kahadb.data.KahaTransactionInfo; import org.apache.activemq.store.kahadb.data.KahaXATransactionId; +import org.apache.activemq.store.kahadb.disk.journal.DataFileFactory; import org.apache.activemq.store.kahadb.disk.journal.Journal.JournalDiskSyncStrategy; import org.apache.activemq.usage.SystemUsage; import org.apache.activemq.util.ServiceStopper; @@ -840,4 +841,8 @@ public void setCleanupOnStop(boolean cleanupOnStop) { public boolean getCleanupOnStop() { return this.letter.getCleanupOnStop(); } + + public void setDataFileFactory(DataFileFactory dataFileFactory) { + this.letter.setDataFileFactory(dataFileFactory); + } } diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java index c21f982560..4e76b3bfee 100644 --- a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java @@ -89,11 +89,8 @@ import org.apache.activemq.store.kahadb.disk.index.BTreeIndex; import org.apache.activemq.store.kahadb.disk.index.BTreeVisitor; import org.apache.activemq.store.kahadb.disk.index.ListIndex; -import org.apache.activemq.store.kahadb.disk.journal.DataFile; -import org.apache.activemq.store.kahadb.disk.journal.Journal; +import org.apache.activemq.store.kahadb.disk.journal.*; import org.apache.activemq.store.kahadb.disk.journal.Journal.JournalDiskSyncStrategy; -import org.apache.activemq.store.kahadb.disk.journal.Location; -import org.apache.activemq.store.kahadb.disk.journal.TargetedDataFileAppender; import org.apache.activemq.store.kahadb.disk.page.Page; import org.apache.activemq.store.kahadb.disk.page.PageFile; import org.apache.activemq.store.kahadb.disk.page.Transaction; @@ -263,6 +260,7 @@ public enum PurgeRecoveredXATransactionStrategy { protected JournalDiskSyncStrategy journalDiskSyncStrategy = JournalDiskSyncStrategy.ALWAYS; protected boolean archiveDataLogs; + protected DataFileFactory dataFileFactory; protected File directoryArchive; protected AtomicLong journalSize = new AtomicLong(0); long journalDiskSyncInterval = 1000; @@ -3282,6 +3280,9 @@ protected Journal createJournal() throws IOException { IOHelper.mkdirs(getDirectoryArchive()); manager.setDirectoryArchive(getDirectoryArchive()); } + if (getDataFileFactory() != null) { + manager.setDataFileFactory(getDataFileFactory()); + } return manager; } @@ -4156,4 +4157,12 @@ private void handleIOException(String taskName, IOException ioe) { LOG.debug(e.getMessage(), e); } } + + public DataFileFactory getDataFileFactory() { + return this.dataFileFactory; + } + + public void setDataFileFactory(DataFileFactory dataFileFactory) { + this.dataFileFactory = dataFileFactory; + } } diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DataFileFactory.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DataFileFactory.java new file mode 100644 index 0000000000..85120323a7 --- /dev/null +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DataFileFactory.java @@ -0,0 +1,23 @@ +/** + * 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.activemq.store.kahadb.disk.journal; + +import java.io.File; + +public interface DataFileFactory { + DataFile create(File file, int number); +} \ No newline at end of file diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DefaultDataFileFactory.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DefaultDataFileFactory.java new file mode 100644 index 0000000000..cd80a0e039 --- /dev/null +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/DefaultDataFileFactory.java @@ -0,0 +1,27 @@ +/** + * 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.activemq.store.kahadb.disk.journal; + +import java.io.File; + +public class DefaultDataFileFactory implements DataFileFactory { + + @Override + public DataFile create(File file, int number) { + return new DataFile(file, number); + } +} \ No newline at end of file diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/Journal.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/Journal.java index f565f9c6a6..754f280287 100644 --- a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/Journal.java +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/journal/Journal.java @@ -241,6 +241,7 @@ private static byte[] createEofBatchAndLocationRecord() { private long cleanupInterval = DEFAULT_CLEANUP_INTERVAL; protected JournalDiskSyncStrategy journalDiskSyncStrategy = JournalDiskSyncStrategy.ALWAYS; + protected DataFileFactory dataFileFactory = new DefaultDataFileFactory(); public interface DataFileRemovedListener { void fileRemoved(DataFile datafile); @@ -272,7 +273,7 @@ public boolean accept(File dir, String n) { String n = file.getName(); String numStr = n.substring(filePrefix.length(), n.length()-fileSuffix.length()); int num = Integer.parseInt(numStr); - DataFile dataFile = new DataFile(file, num); + DataFile dataFile = dataFileFactory.create(file, num); fileMap.put(dataFile.getDataFileId(), dataFile); totalLength.addAndGet(dataFile.getLength()); } catch (NumberFormatException e) { @@ -687,7 +688,7 @@ public void run() { private DataFile newDataFile() throws IOException { int nextNum = nextDataFileId++; File file = getFile(nextNum); - DataFile nextWriteFile = new DataFile(file, nextNum); + DataFile nextWriteFile = dataFileFactory.create(file, nextNum); preallocateEntireJournalDataFile(nextWriteFile.appendRandomAccessFile()); return nextWriteFile; } @@ -697,7 +698,7 @@ public DataFile reserveDataFile() { synchronized (dataFileIdLock) { int nextNum = nextDataFileId++; File file = getFile(nextNum); - DataFile reservedDataFile = new DataFile(file, nextNum); + DataFile reservedDataFile = dataFileFactory.create(file, nextNum); synchronized (currentDataFile) { fileMap.put(reservedDataFile.getDataFileId(), reservedDataFile); fileByFileMap.put(file, reservedDataFile); @@ -1164,6 +1165,14 @@ public void setDataFileRemovedListener(DataFileRemovedListener dataFileRemovedLi this.dataFileRemovedListener = dataFileRemovedListener; } + public void setDataFileFactory(DataFileFactory dataFileFactory) { + this.dataFileFactory = dataFileFactory; + } + + public DataFileFactory getDataFileFactory() { + return this.dataFileFactory; + } + public static class WriteCommand extends LinkedNode { public final Location location; public final ByteSequence data; diff --git a/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/JournalArchiveTest.java b/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/JournalArchiveTest.java index 2a8bd60165..a8090d37e5 100644 --- a/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/JournalArchiveTest.java +++ b/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/JournalArchiveTest.java @@ -22,6 +22,9 @@ import org.apache.activemq.broker.region.policy.PolicyMap; import org.apache.activemq.command.ActiveMQQueue; import org.apache.activemq.store.kahadb.disk.journal.DataFile; +import org.apache.activemq.store.kahadb.disk.journal.DataFileFactory; +import org.apache.activemq.store.kahadb.disk.journal.DefaultDataFileFactory; +import org.apache.activemq.store.kahadb.disk.journal.ErrorDataFileFactory; import org.junit.After; import org.junit.Test; import org.slf4j.Logger; @@ -54,6 +57,7 @@ public class JournalArchiveTest { private BrokerService broker = null; private final Destination destination = new ActiveMQQueue("Test"); private KahaDBPersistenceAdapter adapter; + private DataFileFactory dataFileFactory; protected void startBroker() throws Exception { doStartBroker(true); @@ -104,6 +108,7 @@ protected void configurePersistence(BrokerService brokerService) throws Exceptio adapter.setCheckForCorruptJournalFiles(true); adapter.setArchiveDataLogs(true); + adapter.setDataFileFactory(dataFileFactory); } @After @@ -119,16 +124,8 @@ public void tearDown() throws Exception { public void testRecoveryOnArchiveFailure() throws Exception { final AtomicInteger atomicInteger = new AtomicInteger(); - System.setSecurityManager(new SecurityManager() { - public void checkPermission(Permission perm) {} - public void checkPermission(Permission perm, Object context) {} + this.dataFileFactory = new ErrorDataFileFactory(); - public void checkWrite(String file) { - if (file.contains(DEFAULT_ARCHIVE_DIRECTORY) && atomicInteger.incrementAndGet() > 4) { - throw new SecurityException("No Perms to write to archive times:" + atomicInteger.get()); - } - } - }); startBroker(); int sent = produceMessagesToConsumeMultipleDataFiles(50); @@ -151,7 +148,7 @@ public void run() { assertTrue("broker got shutdown on page in error", gotShutdown.await(10, TimeUnit.SECONDS)); // no restrictions - System.setSecurityManager(null); + this.dataFileFactory = new DefaultDataFileFactory(); int numFilesAfterRestart = 0; try { diff --git a/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/journal/ErrorDataFileFactory.java b/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/journal/ErrorDataFileFactory.java new file mode 100644 index 0000000000..e20f5061d8 --- /dev/null +++ b/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/journal/ErrorDataFileFactory.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 + * + * 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.activemq.store.kahadb.disk.journal; + +import org.apache.activemq.util.IOHelper; + +import java.io.File; +import java.io.IOException; + +import static org.apache.activemq.store.kahadb.disk.journal.Journal.DEFAULT_ARCHIVE_DIRECTORY; + +public class ErrorDataFileFactory implements DataFileFactory { + + @Override + public DataFile create(File file, int number) { + return new ErrorDataFile(file, number); + } + + public static class ErrorDataFile extends DataFile { + + ErrorDataFile(File file, int number) { + super(file, number); + } + + @Override + public synchronized void move(File targetDirectory) throws IOException { + if (targetDirectory.getName().contains(DEFAULT_ARCHIVE_DIRECTORY) && this.dataFileId > 4) { + throw new SecurityException("No Perms to write to archive times:" + this.dataFileId); + } + IOHelper.moveFile(file, targetDirectory); + } + } +} From 15c6f7f4ba699749bca623e4792f782bd2fd88aa Mon Sep 17 00:00:00 2001 From: Matt Pavlovich Date: Sun, 16 Nov 2025 09:38:11 -0600 Subject: [PATCH 05/10] Add support for Java 25 in CI configurations Ensure builds under Java 21 will still work with Security Manager Only run required tests --- .github/workflows/ci-nightly.yml | 4 ++-- .github/workflows/ci-quick.yml | 9 +++++---- pom.xml | 12 +++++++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index ec22a81b87..93da3ea4ad 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -57,7 +57,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-24.04, ubuntu-22.04, macos-26, macos-15, windows-2025, windows-2022 ] - java-version: [ 17, 21 ] + java-version: [ 17, 21, 25 ] runs-on: ${{ matrix.os }} @@ -69,7 +69,7 @@ jobs: java-version: ${{ matrix.java-version }} distribution: temurin - name: Test - run: mvn -B -e -fae test + run: mvn -B -e -fae verify - name: Upload Test Results if: (!cancelled()) uses: actions/upload-artifact@v4 diff --git a/.github/workflows/ci-quick.yml b/.github/workflows/ci-quick.yml index 8671dcc0a6..e52a6fe89d 100644 --- a/.github/workflows/ci-quick.yml +++ b/.github/workflows/ci-quick.yml @@ -33,7 +33,7 @@ jobs: strategy: matrix: os: [ ubuntu-24.04, macos-26, windows-2025 ] - java-version: [ 17, 21 ] + java-version: [ 17, 21, 25 ] runs-on: ${{ matrix.os }} @@ -64,10 +64,11 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: - java-version: 17 + # temporary using 25 until all tests pass on Java 25 - to be changed back to 17 for quick. 25 will run nightly only + java-version: 25 distribution: temurin - name: Test - run: mvn -B -e -fae test + run: mvn -B -e -fae verify -Pactivemq.tests-quick - name: Upload Test Results if: (!cancelled()) uses: actions/upload-artifact@v4 @@ -81,4 +82,4 @@ jobs: large_files: true report_individual_runs: true report_suite_logs: error - files: '**/target/surefire-reports/*.xml' + files: '**/target/surefire-reports/*.xml' \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4666f439ee..af190fea64 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - -Djava.security.manager=allow + activemq-${project.version} Apache ActiveMQ @@ -1449,5 +1449,15 @@ -Xdoclint:none + + + allow-securitymanager + + [18,23] + + + -Djava.security.manager=allow + + From 51ccb58ecf91555b58f1e12c5ea7e9b9d2aa2155 Mon Sep 17 00:00:00 2001 From: Jean-Louis Monteiro Date: Fri, 19 Dec 2025 13:02:25 +0100 Subject: [PATCH 06/10] AMQ-9825: ActiveMQ on Java 25 Use Java 25 compatible version of Mockito Use Mockito Agent because self attaching an agent is now unavailable since Java 21+ Split integration tests (MRJAR dependent) into a specific integration-test phase so they use the jar in the classpath Do not rely on activeByDefault because when other profiles activate, quick becomes inactive --- Jenkinsfile | 10 +---- .../apache/activemq/broker/BrokerService.java | 2 +- .../activemq/thread/TaskRunnerFactory.java | 21 ++++----- activemq-unit-tests/pom.xml | 44 ++++++++++++++++++- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9338b7e46c..100a3b8c73 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -49,7 +49,6 @@ pipeline { choice(name: 'nodeLabel', choices: [ 'ubuntu', 's390x', 'arm', 'Windows' ]) choice(name: 'jdkVersion', choices: ['jdk_17_latest', 'jdk_21_latest', 'jdk_25_latest', 'jdk_17_latest_windows', 'jdk_21_latest_windows', 'jdk_25_latest_windows']) booleanParam(name: 'deployEnabled', defaultValue: false) - booleanParam(name: 'parallelTestsEnabled', defaultValue: true) booleanParam(name: 'sonarEnabled', defaultValue: false) booleanParam(name: 'testsEnabled', defaultValue: true) } @@ -137,13 +136,8 @@ pipeline { // all tests is very very long (10 hours on Apache Jenkins) // sh 'mvn -B -e test -pl activemq-unit-tests -Dactivemq.tests=all' script { - if (params.parallelTestsEnabled == 'true') { - sh 'echo "Running parallel-tests ..."' - sh 'mvn -B -e -fae -Pparallel-tests test -Dsurefire.rerunFailingTestsCount=3' - } else { - sh 'echo "Running tests ..."' - sh 'mvn -B -e -fae test -Dsurefire.rerunFailingTestsCount=3' - } + sh 'echo "Running tests ..."' + sh 'mvn -B -e -fae verify -Pactivemq.tests-quick' } } post { diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java b/activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java index 1eeb6fb8b4..e51d521480 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java +++ b/activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java @@ -1898,7 +1898,7 @@ public boolean isVirtualThreadTaskRunner() { return virtualThreadTaskRunner; } - @Experimental("Tech Preview for Virtaul Thread support") + @Experimental("Tech Preview for Virtual Thread support") public void setVirtualThreadTaskRunner(boolean virtualThreadTaskRunner) { this.virtualThreadTaskRunner = virtualThreadTaskRunner; } diff --git a/activemq-client/src/main/java/org/apache/activemq/thread/TaskRunnerFactory.java b/activemq-client/src/main/java/org/apache/activemq/thread/TaskRunnerFactory.java index 3c872bef3c..28f834efcb 100644 --- a/activemq-client/src/main/java/org/apache/activemq/thread/TaskRunnerFactory.java +++ b/activemq-client/src/main/java/org/apache/activemq/thread/TaskRunnerFactory.java @@ -240,10 +240,7 @@ public void uncaughtException(final Thread t, final Throwable e) { } protected ExecutorService createVirtualThreadExecutor() { - if(!(Runtime.version().feature() >= 21)) { - LOG.error("Virtual Thread support requires JDK 21 or higher"); - throw new IllegalStateException("Virtual Thread support requires JDK 21 or higher"); - } + assertJDK21VirtualThreadSupport(); try { Class virtualThreadExecutorClass = Class.forName("org.apache.activemq.thread.VirtualThreadExecutor", false, threadClassLoader); @@ -253,7 +250,7 @@ protected ExecutorService createVirtualThreadExecutor() { throw new IllegalStateException("VirtualThreadExecutor not returned"); } LOG.info("VirtualThreadExecutor initialized name:{}", name); - return ExecutorService.class.cast(result); + return (ExecutorService) result; } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException e) { LOG.error("VirtualThreadExecutor class failed to load", e); throw new IllegalStateException(e); @@ -261,10 +258,7 @@ protected ExecutorService createVirtualThreadExecutor() { } protected TaskRunner createVirtualThreadTaskRunner(Executor executor, Task task, int maxIterations) { - if(!(Runtime.version().feature() >= 21)) { - LOG.error("Virtual Thread support requires JDK 21 or higher"); - throw new IllegalStateException("Virtual Thread support requires JDK 21 or higher"); - } + assertJDK21VirtualThreadSupport(); try { Class virtualThreadTaskRunnerClass = Class.forName("org.apache.activemq.thread.VirtualThreadTaskRunner", false, threadClassLoader); @@ -273,13 +267,20 @@ protected TaskRunner createVirtualThreadTaskRunner(Executor executor, Task task, if(!TaskRunner.class.isAssignableFrom(result.getClass())) { throw new IllegalStateException("VirtualThreadTaskRunner not returned"); } - return TaskRunner.class.cast(result); + return (TaskRunner) result; } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException | InstantiationException | IllegalArgumentException e) { LOG.error("VirtualThreadTaskRunner class failed to load", e); throw new IllegalStateException(e); } } + private void assertJDK21VirtualThreadSupport() { + if(!(Runtime.version().feature() >= 21)) { + LOG.error("Virtual Thread support requires JDK 21 or higher"); + throw new IllegalStateException("Virtual Thread support requires JDK 21 or higher"); + } + } + public ExecutorService getExecutor() { return executorRef.get(); diff --git a/activemq-unit-tests/pom.xml b/activemq-unit-tests/pom.xml index 2e4d088dbb..8cebb69fad 100644 --- a/activemq-unit-tests/pom.xml +++ b/activemq-unit-tests/pom.xml @@ -465,6 +465,18 @@ **/ClientIdFilterDispatchPolicyTest.java **/StartAndConcurrentStopBrokerTest.java **/BlobTransferPolicyUriTest.java + + + **/VirtualThreadTaskRunnerBrokerTest.java + **/DLQRetryTest.java + **/JmxAuditLogTest.java + **/JmxCreateNCTest.java @@ -507,6 +519,37 @@ + + org.apache.maven.plugins + maven-failsafe-plugin + 3.5.2 + + + + integration-test + verify + + + + + 1 + false + false + + ${project.build.directory}/ + true + true + false + + -Xmx512m -javaagent:${org.mockito:mockito-core:jar} + + **/VirtualThreadTaskRunnerBrokerTest.java + **/DLQRetryTest.java + **/JmxAuditLogTest.java + **/JmxCreateNCTest.java + + + org.apache.maven.plugins @@ -717,7 +760,6 @@ activemq.tests-quick - true activemq.tests quick From 11b6fa3ed57b763aeb1bddc61e0895f515442b8d Mon Sep 17 00:00:00 2001 From: Jean-Louis Monteiro Date: Thu, 5 Feb 2026 14:50:27 +0100 Subject: [PATCH 07/10] Remove unused import for AccessController in SubjectShim.java because the API will be removed anyways --- .../main/java24/org/apache/activemq/broker/jmx/SubjectShim.java | 1 - 1 file changed, 1 deletion(-) diff --git a/activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java b/activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java index d90728014f..f112b45b0f 100644 --- a/activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java +++ b/activemq-broker/src/main/java24/org/apache/activemq/broker/jmx/SubjectShim.java @@ -17,7 +17,6 @@ package org.apache.activemq.broker.jmx; import javax.security.auth.Subject; -import java.security.AccessController; /** * [AMQ-9563] JDK JAAS API conversion assistance From 9b5e101fe9ae55a0ee900f7921064c67782a96b7 Mon Sep 17 00:00:00 2001 From: Jean-Louis Monteiro Date: Thu, 5 Feb 2026 14:50:52 +0100 Subject: [PATCH 08/10] Do not use * imports --- .../org/apache/activemq/store/kahadb/MessageDatabase.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java index 4e76b3bfee..2709817d01 100644 --- a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java @@ -89,8 +89,12 @@ import org.apache.activemq.store.kahadb.disk.index.BTreeIndex; import org.apache.activemq.store.kahadb.disk.index.BTreeVisitor; import org.apache.activemq.store.kahadb.disk.index.ListIndex; -import org.apache.activemq.store.kahadb.disk.journal.*; +import org.apache.activemq.store.kahadb.disk.journal.DataFile; +import org.apache.activemq.store.kahadb.disk.journal.DataFileFactory; +import org.apache.activemq.store.kahadb.disk.journal.Journal; import org.apache.activemq.store.kahadb.disk.journal.Journal.JournalDiskSyncStrategy; +import org.apache.activemq.store.kahadb.disk.journal.Location; +import org.apache.activemq.store.kahadb.disk.journal.TargetedDataFileAppender; import org.apache.activemq.store.kahadb.disk.page.Page; import org.apache.activemq.store.kahadb.disk.page.PageFile; import org.apache.activemq.store.kahadb.disk.page.Transaction; From a17b79551d39ac31ee2485bd7a52f5fb59bcfdd0 Mon Sep 17 00:00:00 2001 From: Jean-Louis Monteiro Date: Thu, 5 Feb 2026 14:52:36 +0100 Subject: [PATCH 09/10] Attempt to build the MRJAR earlier so tests can use it and we can avoid the failsafe integration tests --- activemq-broker/pom.xml | 10 +++++++++ activemq-unit-tests/pom.xml | 43 ------------------------------------- 2 files changed, 10 insertions(+), 43 deletions(-) diff --git a/activemq-broker/pom.xml b/activemq-broker/pom.xml index 15326983ce..14a6e0e487 100644 --- a/activemq-broker/pom.xml +++ b/activemq-broker/pom.xml @@ -209,6 +209,16 @@ maven-jar-plugin + + + default-jar + process-test-classes + + jar + + test-jar diff --git a/activemq-unit-tests/pom.xml b/activemq-unit-tests/pom.xml index 8cebb69fad..78b0293807 100644 --- a/activemq-unit-tests/pom.xml +++ b/activemq-unit-tests/pom.xml @@ -465,18 +465,6 @@ **/ClientIdFilterDispatchPolicyTest.java **/StartAndConcurrentStopBrokerTest.java **/BlobTransferPolicyUriTest.java - - - **/VirtualThreadTaskRunnerBrokerTest.java - **/DLQRetryTest.java - **/JmxAuditLogTest.java - **/JmxCreateNCTest.java @@ -519,37 +507,6 @@ - - org.apache.maven.plugins - maven-failsafe-plugin - 3.5.2 - - - - integration-test - verify - - - - - 1 - false - false - - ${project.build.directory}/ - true - true - false - - -Xmx512m -javaagent:${org.mockito:mockito-core:jar} - - **/VirtualThreadTaskRunnerBrokerTest.java - **/DLQRetryTest.java - **/JmxAuditLogTest.java - **/JmxCreateNCTest.java - - - org.apache.maven.plugins From 1de8b1cb24394027ec9e789ae56b6abecdf1959d Mon Sep 17 00:00:00 2001 From: Jean-Louis Monteiro Date: Tue, 10 Feb 2026 07:55:02 +0100 Subject: [PATCH 10/10] Update Maven Enforcer Plugin to require Java 24+ for builds --- pom.xml | 76 +++++++++++++++------------------------------------------ 1 file changed, 20 insertions(+), 56 deletions(-) diff --git a/pom.xml b/pom.xml index af190fea64..e86aa93dc0 100644 --- a/pom.xml +++ b/pom.xml @@ -1121,39 +1121,6 @@ - - org.apache.maven.plugins - maven-enforcer-plugin - - - enforce-maven - - enforce - - - - - 3.0.5 - - - - - - enforce-java-version - - enforce - - - - - [17,) - You must use Java 17+ to build. - - - - - - org.apache.geronimo.genesis.plugins tools-maven-plugin @@ -1271,29 +1238,6 @@ - org.codehaus.mojo taglist-maven-plugin @@ -1337,6 +1281,26 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-java-version + + enforce + + + + + [24,) + You must use Java 24+ to build (we leverage MRJAR). + + + + + + org.apache.maven.plugins maven-surefire-plugin