Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}

Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason to use verify here more than test ? I'm just curious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it was mostly due to the introduction of failsafe to delay the execution of tests using the MRJAR because the jar is created only after the test phase. So tests using MRJAR were postponed to run only during the integration test phase. So if you use test and not verify you won't run them.
In the end, I could have reverted this because Robbie requested instead to change the phase of the JAR plugin so the MRJAR is built in the process classes phase and therefor it's visible to the test plugin. Does not hurt. Could have been removed

- name: Upload Test Results
if: (!cancelled())
uses: actions/upload-artifact@v4
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/ci-quick.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}

Expand Down Expand Up @@ -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
Expand All @@ -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'
20 changes: 7 additions & 13 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ 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)
booleanParam(name: 'testsEnabled', defaultValue: true)
}
Expand Down Expand Up @@ -77,12 +76,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'
Expand Down Expand Up @@ -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 {
Expand Down
39 changes: 38 additions & 1 deletion activemq-broker/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<!-- Do jar creation earlier, before the "test" phase, so that the
multi-release-jar content is visible to any dependent modules,
enabling them to use the relevant classes during their tests. -->
<id>default-jar</id>
<phase>process-test-classes</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
<execution>
<goals>
<goal>test-jar</goal>
Expand Down Expand Up @@ -242,7 +252,7 @@
</plugins>
</build>
</profile>
<profile>
<profile>
<id>activemq.tests-autoTransport</id>
<activation>
<property>
Expand All @@ -263,5 +273,32 @@
</plugins>
</build>
</profile>
<profile>
<id>jdk24-plus</id>
<activation>
<jdk>[24,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>java24-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>24</release> <!-- Specific Java version for alternative classes -->
<compileSourceRoots>${project.basedir}/src/main/java24</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "";
Expand Down
Original file line number Diff line number Diff line change
@@ -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());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* 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;

/**
* [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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -253,18 +250,15 @@ 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);
}
}

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);
Expand All @@ -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");
}
}

Comment on lines +277 to +283
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup seems fine, but a thought for later would be....is there any need for all the reflection above and this runtime version checking, when the client jar is already a multi-release jar requiring Java 21 (and soon 24[/25]) to release it? Could maybe have a [couple variants of] trivial delegate class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a refactoring of @mattrpav 's code. So I'd let him reply.
I agree that having the assertion to fail would be weird because that would mean the JVM could not read the MRJAR but still run in some way this class.


public ExecutorService getExecutor() {
return executorRef.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
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.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;
Expand Down Expand Up @@ -263,6 +264,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;
Expand Down Expand Up @@ -3282,6 +3284,9 @@ protected Journal createJournal() throws IOException {
IOHelper.mkdirs(getDirectoryArchive());
manager.setDirectoryArchive(getDirectoryArchive());
}
if (getDataFileFactory() != null) {
manager.setDataFileFactory(getDataFileFactory());
}
return manager;
}

Expand Down Expand Up @@ -4156,4 +4161,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;
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
Loading