diff --git a/.gitignore b/.gitignore
index e009c51037..82f0757511 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,6 @@ core/tests/org.openjdk.jmc.flightrecorder.rules.jdk.test/baseline/Generated_JfrR
# Ignore configuration directories generated by spotbugs
**/configuration/spotbugs
+
+# Ignore vendor specific agent instructions
+CLAUDE.md
diff --git a/application/org.openjdk.jmc.feature.core/feature.xml b/application/org.openjdk.jmc.feature.core/feature.xml
index 1135edbb96..e13b98c47f 100644
--- a/application/org.openjdk.jmc.feature.core/feature.xml
+++ b/application/org.openjdk.jmc.feature.core/feature.xml
@@ -245,7 +245,7 @@
unpack="false"/>
+
+
METHODS_TO_IGNORE = new HashSet<>(
+ Arrays.asList("registerMBean", "unregisterMBean")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static final LogHandler logHandler = new JulLoggerAdapter(Logger.getLogger("org.openjdk.jmc.jolokia")); //$NON-NLS-1$
+
+ public static JolokiaContext proxyJolokiaContext() {
+ return (JolokiaContext) Proxy.newProxyInstance(JmcJolokiaContext.class.getClassLoader(),
+ new Class[] {JolokiaContext.class}, new InvocationHandler() {
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if ("getAgentDetails".equals(method.getName())) { //$NON-NLS-1$
+ return new AgentDetails("jmc"); //$NON-NLS-1$
+ } else if (METHODS_TO_IGNORE.contains(method.getName())) {
+ return null;
+ } else if (method.getDeclaringClass().getName().equals(LogHandler.class.getName())) {
+ // Redirect logs to java util logging
+ return method.invoke(logHandler, args);
+ }
+ throw new UnsupportedOperationException(
+ method.getName() + " is not supported for JMC Jolokia context"); //$NON-NLS-1$
+ }
+ });
+ }
+
+}
+
+/**
+ * Simple adapter based on
+ * https://github.com/jolokia/jolokia/blob/main/server/core/src/main/java/org/jolokia/server/core/service/impl/JulLogHandler.java
+ * (Which is not directly accessible due to OSGi constraints)
+ */
+class JulLoggerAdapter implements LogHandler {
+
+ private final Logger julLogger;
+
+ public JulLoggerAdapter(Logger julLogger) {
+ this.julLogger = julLogger;
+ }
+
+ @Override
+ public void debug(String message) {
+ julLogger.finer(message);
+ }
+
+ @Override
+ public void error(String message, Throwable err) {
+ julLogger.log(Level.SEVERE, message, err);
+ }
+
+ @Override
+ public void info(String message) {
+ julLogger.info(message);
+ }
+
+ @Override
+ public boolean isDebug() {
+ return julLogger.isLoggable(Level.FINER);
+ }
+}
diff --git a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnection.java b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnection.java
index 6ce14ce394..69d3a8f502 100644
--- a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnection.java
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnection.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024, 2025, Kantega AS. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Kantega AS. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -35,31 +35,35 @@
import java.io.IOException;
import java.lang.management.ManagementFactory;
+import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Map;
import java.util.Optional;
import javax.management.AttributeNotFoundException;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
+import javax.management.ReflectionException;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.openmbean.TabularData;
-import org.jolokia.client.JolokiaClient;
-import org.jolokia.client.jmxadapter.RemoteJmxAdapter;
+import org.jolokia.core.service.serializer.SerializeOptions;
import org.jolokia.service.serializer.JolokiaSerializer;
-import org.jolokia.server.core.service.serializer.SerializeOptions;
+import org.openjdk.jmc.rjmx.common.ConnectionDecorator;
/**
* Make JMC specific adjustments to Jolokia JMX connection. May consider to use the decorator
* pattern if differences are big, but for now subclass
*/
-public class JmcJolokiaJmxConnection extends RemoteJmxAdapter {
+public class JmcJolokiaJmxConnection extends ConnectionDecorator {
private static final String UNKNOWN = "Unknown"; //$NON-NLS-1$
private static final String DIAGNOSTIC_OPTIONS = "com.sun.management:type=DiagnosticCommand"; //$NON-NLS-1$
@@ -74,13 +78,15 @@ public class JmcJolokiaJmxConnection extends RemoteJmxAdapter {
private static final String ARGUMENT_TYPE = PREFIX + "arg.type"; //$NON-NLS-1$
private static final String ARGUMENT_OPTION = PREFIX + "arg.isOption"; //$NON-NLS-1$
private static final String ARGUMENT_MULITPLE = PREFIX + "arg.isMultiple"; //$NON-NLS-1$
+ private Map mbeanInfoCache = new HashMap<>();
- public JmcJolokiaJmxConnection(JolokiaClient client) throws IOException {
- super(client);
+ public JmcJolokiaJmxConnection(MBeanServerConnection delegate) {
+ super(delegate);
}
@Override
- public MBeanInfo getMBeanInfo(ObjectName name) throws InstanceNotFoundException, IOException {
+ public MBeanInfo getMBeanInfo(ObjectName name)
+ throws InstanceNotFoundException, ReflectionException, IOException, IntrospectionException {
MBeanInfo mBeanInfo = super.getMBeanInfo(name);
// the diagnostic options tab and memory relies on descriptor info in MBeanInfo,
// modify descriptors the first time
@@ -115,7 +121,7 @@ private Optional checkForLocalOperationInfo(ObjectName name) {
@Override
public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature)
- throws InstanceNotFoundException, MBeanException, IOException {
+ throws InstanceNotFoundException, MBeanException, IOException, ReflectionException {
if (params != null) {
for (int i = 0; i < params.length; i++) {
@@ -211,14 +217,14 @@ private Descriptor buildArgument(MBeanParameterInfo parameter) {
@Override
public boolean isInstanceOf(ObjectName objectName, String type) throws InstanceNotFoundException, IOException {
- if ("java.lang.management.OperatingSystemMXBean".equals(type) //$NON-NLS-1$
- && "com.sun.management.internal.OperatingSystemImpl" //$NON-NLS-1$
- .equals(this.getMBeanInfo(objectName).getClassName())) {
- return true;
- }
try {
+ if ("java.lang.management.OperatingSystemMXBean".equals(type) //$NON-NLS-1$
+ && "com.sun.management.internal.OperatingSystemImpl" //$NON-NLS-1$
+ .equals(this.getMBeanInfo(objectName).getClassName())) {
+ return true;
+ }
return super.isInstanceOf(objectName, type);
- } catch (NoClassDefFoundError | UnsatisfiedLinkError e) {
+ } catch (NoClassDefFoundError | UnsatisfiedLinkError | ReflectionException | IntrospectionException e) {
//Handle this until it is fixed in jolokia https://github.com/jolokia/jolokia/issues/666
return false;
}
diff --git a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnector.java b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnector.java
index 13b93bf5e9..566be1e27c 100644
--- a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnector.java
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnector.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024, 2025, Kantega AS. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Kantega AS. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -33,14 +33,13 @@
*/
package org.openjdk.jmc.jolokia;
-import java.io.IOException;
import java.util.Map;
+import javax.management.MBeanServerConnection;
import javax.management.remote.JMXServiceURL;
+import javax.security.auth.Subject;
-import org.jolokia.client.JolokiaClientBuilder;
import org.jolokia.client.jmxadapter.JolokiaJmxConnector;
-import org.jolokia.client.jmxadapter.RemoteJmxAdapter;
public class JmcJolokiaJmxConnector extends JolokiaJmxConnector {
@@ -49,8 +48,13 @@ public JmcJolokiaJmxConnector(JMXServiceURL serviceURL, Map environme
}
@Override
- protected RemoteJmxAdapter instantiateAdapter(JolokiaClientBuilder clientBuilder, Map mergedEnv)
- throws IOException {
- return new JmcJolokiaJmxConnection(clientBuilder.build());
+ public MBeanServerConnection getMBeanServerConnection() {
+ return new JmcJolokiaJmxConnection(super.getMBeanServerConnection());
}
+
+ @Override
+ public MBeanServerConnection getMBeanServerConnection(Subject delegationSubject) {
+ return new JmcJolokiaJmxConnection(super.getMBeanServerConnection(delegationSubject));
+ }
+
}
diff --git a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaPlugin.java b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaPlugin.java
index 47e2e9bb15..5489d7035e 100644
--- a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaPlugin.java
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaPlugin.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2025, Kantega AS. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Kantega AS. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -33,17 +33,7 @@
*/
package org.openjdk.jmc.jolokia;
-import java.util.Arrays;
-import java.util.TreeSet;
-
-import org.jolokia.server.core.config.ConfigKey;
-import org.jolokia.server.core.config.StaticConfiguration;
-import org.jolokia.server.core.detector.ServerDetector;
-import org.jolokia.server.core.restrictor.AllowAllRestrictor;
-import org.jolokia.server.core.service.JolokiaServiceManagerFactory;
import org.jolokia.server.core.service.api.JolokiaContext;
-import org.jolokia.server.core.service.api.JolokiaServiceManager;
-import org.jolokia.server.core.service.impl.JulLogHandler;
import org.openjdk.jmc.jolokia.preferences.PreferenceConstants;
import org.openjdk.jmc.ui.MCAbstractUIPlugin;
@@ -72,11 +62,7 @@ public boolean shouldRunDiscovery() {
*/
@Override
public JolokiaContext getJolokiaContext() {
- StaticConfiguration configuration = new StaticConfiguration(ConfigKey.AGENT_ID, "jmc");//$NON-NLS-1$
- JolokiaServiceManager serviceManager = JolokiaServiceManagerFactory.createJolokiaServiceManager(configuration,
- new JulLogHandler(PLUGIN_ID), new AllowAllRestrictor(),
- logHandler -> new TreeSet(Arrays.asList(ServerDetector.FALLBACK)));
- return serviceManager.start();
+ return JmcJolokiaContext.proxyJolokiaContext();
}
@Override
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/META-INF/MANIFEST.MF b/application/tests/org.openjdk.jmc.jolokia.test/META-INF/MANIFEST.MF
index ad701f71c4..beeba2051c 100644
--- a/application/tests/org.openjdk.jmc.jolokia.test/META-INF/MANIFEST.MF
+++ b/application/tests/org.openjdk.jmc.jolokia.test/META-INF/MANIFEST.MF
@@ -16,3 +16,6 @@ Require-Bundle: org.junit,
org.hamcrest,
org.osgi.service.servlet;bundle-version="2.0.0"
Automatic-Module-Name: org.openjdk.jmc.jolokia.test
+Import-Package: org.jolokia.server.core.config;version="2.5.1",
+ org.jolokia.server.core.service.api;version="2.5.1",
+ org.jolokia.service.discovery;version="2.5.1"
\ No newline at end of file
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/pom.xml b/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
index 530cee570f..7fea70e3e9 100644
--- a/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
+++ b/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
@@ -1,7 +1,7 @@
Couldnt send discovery message from /127.0.0.1: java.net.BindException: Can't assign requested address
- // D> --> Exception during lookup: java.util.concurrent.ExecutionException:
- // org.jolokia.service.discovery.MulticastUtil$CouldntSendDiscoveryPacketException:
- // Can't send discovery UDP packet from /127.0.0.1: Can't assign requested address'
+ // Multicast discovery does not work on macOS due to network stack limitations
+ // 'D> --> Couldnt send discovery message from /127.0.0.1:
+ // java.net.BindException: Can't assign requested address
+ // D> --> Exception during lookup: java.util.concurrent.ExecutionException:
+ // org.jolokia.service.discovery.MulticastUtil$CouldntSendDiscoveryPacketException:
+ // Can't send discovery UDP packet from /127.0.0.1: Can't assign requested
+ // address'
// We get test coverage on both Linux and Windows
return;
@@ -229,11 +226,7 @@ public boolean shouldRunDiscovery() {
@Override
public JolokiaContext getJolokiaContext() {
- StaticConfiguration configuration = new StaticConfiguration(ConfigKey.AGENT_ID, "jolokiatest");
- JolokiaServiceManager serviceManager = JolokiaServiceManagerFactory.createJolokiaServiceManager(configuration,
- new StdoutLogHandler(true), new AllowAllRestrictor(),
- logHandler -> new TreeSet(Arrays.asList(ServerDetector.FALLBACK)));
- return serviceManager.start();
+ return JmcJolokiaContext.proxyJolokiaContext();
}
@Override
diff --git a/application/uitests/org.openjdk.jmc.console.uitest/src/test/java/org/openjdk/jmc/console/uitest/DiagnosticCommandsTabTest.java b/application/uitests/org.openjdk.jmc.console.uitest/src/test/java/org/openjdk/jmc/console/uitest/DiagnosticCommandsTabTest.java
index e004ff9bc3..8e0ba03ff4 100644
--- a/application/uitests/org.openjdk.jmc.console.uitest/src/test/java/org/openjdk/jmc/console/uitest/DiagnosticCommandsTabTest.java
+++ b/application/uitests/org.openjdk.jmc.console.uitest/src/test/java/org/openjdk/jmc/console/uitest/DiagnosticCommandsTabTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -186,10 +186,14 @@ public void testOutputUpdated() {
@Test
public void testStartFlightRecording() {
commandTable.select("JFR.start");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.select(true, "name");
params.enterText("");
executeButton.click();
- sleep(500);
+ sleep(MCJemmyBase.isOSX() ? 2000 : 500);
String result = resultTabFolder.getText();
resultTabFolder.closeAll();
@@ -203,14 +207,18 @@ public void testStartFlightRecording() {
String recordingIdentifier = matcher.group(1);
commandTable.select("JFR.check");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.select(true, recording_parameter_name);
params.enterText(recordingIdentifier);
executeButton.click();
- sleep(500);
+ sleep(MCJemmyBase.isOSX() ? 2000 : 500);
result = resultTabFolder.getText();
resultTabFolder.closeAll();
- String expectedOutput = "Recording \\d+:.*name=" + recordingIdentifier + ".* \\(running\\).*";
+ String expectedOutput = "Recording " + recordingIdentifier + ":.*\\(running\\).*";
Assert.assertTrue(
"Output from JFR.check diagnostic command" + " is not matching expected pattern. Actual output was: '"
@@ -218,12 +226,16 @@ public void testStartFlightRecording() {
patternMatcher(result, expectedOutput));
commandTable.select("JFR.stop");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.select(true, recording_parameter_name);
params.enterText(recordingIdentifier);
executeButton.click();
- sleep(500);
+ sleep(MCJemmyBase.isOSX() ? 2000 : 500);
result = resultTabFolder.getText();
- expectedOutput = "Stopped [recording ]*[\"Recording-]*" + recordingIdentifier + ".*";
+ expectedOutput = "Stopped [recording ]*.*";
Assert.assertTrue(
"Output from JFR.stop diagnostic command" + " is not matching expected pattern. Actual output was: '"
+ result + "'. Expected output was: '" + expectedOutput + '\'',
@@ -234,19 +246,39 @@ public void testStartFlightRecording() {
public void testStartNamedFlightRecording() {
String recordingName = getRandomRecordingName();
commandTable.select("JFR.start");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(1000);
+ }
params.select(true, "name");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.enterText(recordingName);
executeButton.click();
- sleep(500);
- String result = resultTabFolder.getText();
+ sleep(MCJemmyBase.isOSX() ? 2000 : 500);
+ String startResult = resultTabFolder.getText();
resultTabFolder.closeAll();
+ Assert.assertTrue(
+ "JFR.start output doesn't indicate recording started with name '" + recordingName
+ + "'. Actual output: '" + startResult + "'",
+ patternMatcher(startResult, "Started recording") && startResult.contains(recordingName));
commandTable.select("JFR.check");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.select(true, "name");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.enterText(recordingName);
executeButton.click();
- sleep(500);
- result = resultTabFolder.getText();
+ sleep(MCJemmyBase.isOSX() ? 2000 : 500);
+ String result = resultTabFolder.getText();
resultTabFolder.closeAll();
String expectedOutput = "Recording [\\d]+:.*" + recordingName + ".*";
Assert.assertTrue("Output from JFR.check (with name) diagnostic command"
@@ -269,10 +301,18 @@ public void testStartNamedFlightRecording() {
commandTable.select("JFR.dump");
commandTable.select("JFR.check");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.select(true, recording_parameter_name);
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.enterText(recordingId);
executeButton.click();
- sleep(500);
+ sleep(MCJemmyBase.isOSX() ? 2000 : 500);
result = resultTabFolder.getText();
resultTabFolder.closeAll();
Assert.assertTrue("Output from JFR.check (with recording id) diagnostic command"
@@ -281,10 +321,18 @@ public void testStartNamedFlightRecording() {
// stop recording
commandTable.select("JFR.stop");
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.select(true, recording_parameter_name);
+ MCJemmyBase.waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(500);
+ }
params.enterText(recordingId);
executeButton.click();
- sleep(500);
+ sleep(MCJemmyBase.isOSX() ? 2000 : 500);
result = resultTabFolder.getText();
expectedOutput = "Stopped [recording ]*\"?"
+ ((ConnectionHelper.is9u0EAorLater(TEST_CONNECTION)) ? recordingName : recordingId) + ".*";
diff --git a/application/uitests/org.openjdk.jmc.flightrecorder.uitest/src/test/java/org/openjdk/jmc/flightrecorder/uitest/JfrThreadsPageLegacyTest.java b/application/uitests/org.openjdk.jmc.flightrecorder.uitest/src/test/java/org/openjdk/jmc/flightrecorder/uitest/JfrThreadsPageLegacyTest.java
index d7650b24ce..a32acbc25d 100644
--- a/application/uitests/org.openjdk.jmc.flightrecorder.uitest/src/test/java/org/openjdk/jmc/flightrecorder/uitest/JfrThreadsPageLegacyTest.java
+++ b/application/uitests/org.openjdk.jmc.flightrecorder.uitest/src/test/java/org/openjdk/jmc/flightrecorder/uitest/JfrThreadsPageLegacyTest.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2019, 2025, Red Hat Inc. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, Red Hat Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -93,6 +93,7 @@ public void testMenuItemEnablement() {
public void testHideAllThreads() {
final int numSelection = 7;
final int numThreads = threadsTable.getItemCount();
+ System.out.println("[testHideAllThreads] numThreads=" + numThreads + ", numSelection=" + numSelection);
Assert.assertTrue(numThreads > 0 && numThreads >= numSelection);
Assert.assertTrue(chartCanvas.isContextMenuItemEnabled(HIDE_THREAD));
Assert.assertFalse(chartCanvas.isContextMenuItemEnabled(RESET_CHART));
@@ -102,12 +103,17 @@ public void testHideAllThreads() {
// Hide all the threads from the chart
for (int i = 0; i < numSelection; i++) {
+ System.out.println("[testHideAllThreads] Hiding thread " + (i + 1) + " of " + numSelection);
chartCanvas.clickContextMenuItem(HIDE_THREAD);
}
// Once all threads are hidden from the chart, the hide thread menu item will be disabled
- Assert.assertFalse(chartCanvas.isContextMenuItemEnabled(HIDE_THREAD));
- Assert.assertTrue(chartCanvas.isContextMenuItemEnabled(RESET_CHART));
+ boolean hideEnabled = chartCanvas.isContextMenuItemEnabled(HIDE_THREAD);
+ boolean resetEnabled = chartCanvas.isContextMenuItemEnabled(RESET_CHART);
+ System.out.println("[testHideAllThreads] After hiding: HIDE_THREAD enabled=" + hideEnabled
+ + ", RESET_CHART enabled=" + resetEnabled);
+ Assert.assertFalse("HIDE_THREAD should be disabled after hiding all selected threads", hideEnabled);
+ Assert.assertTrue("RESET_CHART should be enabled after hiding threads", resetEnabled);
chartCanvas.clickContextMenuItem(RESET_CHART);
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/base/wrappers/MCJemmyBase.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/base/wrappers/MCJemmyBase.java
index b7134f03af..b6a396a035 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/base/wrappers/MCJemmyBase.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/base/wrappers/MCJemmyBase.java
@@ -584,7 +584,16 @@ public void run() {
}
};
Display.getDefault().syncExec(fetcher);
- return (fetcher.getOutput() == null) ? false : fetcher.getOutput();
+ boolean result = (fetcher.getOutput() == null) ? false : fetcher.getOutput();
+ // Dismiss the context menu by pressing Escape to prevent interference
+ // with subsequent context menu operations, especially on macOS
+ control.keyboard().pushKey(KeyboardButtons.ESCAPE);
+ waitForIdle();
+ if (isOSX()) {
+ sleep(500);
+ }
+ System.out.println("[MCJemmyBase] isContextMenuItemEnabled(\"" + menuItemText + "\") = " + result);
+ return result;
}
/**
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JfrWizard.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JfrWizard.java
index 65126c9118..fda61d0235 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JfrWizard.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JfrWizard.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -84,7 +84,7 @@ public JfrWizard() {
/**
* Get a wrapper for the flight recording wizard
- *
+ *
* @param wizardTitle
* the title of the wizard shell
*/
@@ -92,6 +92,16 @@ public JfrWizard(String wizardTitle) {
wizardDialog = new MCDialog(wizardTitle);
}
+ /**
+ * Get a wrapper for the flight recording wizard using an already found dialog
+ *
+ * @param dialog
+ * the already found dialog
+ */
+ public JfrWizard(MCDialog dialog) {
+ wizardDialog = dialog;
+ }
+
/**
* @return the eventSettingsTree
*/
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java
index d400f3d2d3..f66f641f16 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java
@@ -172,14 +172,12 @@ public void createConnection(
String connectionName = null;
String[] finalPath = null;
if (itemExists(path)) { // if the path specified already exists then it's a folder
- getTree().select(path);
- getTree().contextChoose(ACTION_NEW_CONNECTION_TEXT);
+ selectAndContextChoose(path, ACTION_NEW_CONNECTION_TEXT);
finalPath = Arrays.copyOf(path, path.length + 1); // we need to save the name of the folder path
finalPath[finalPath.length - 1] = getDefaultConnectionName(host, port); // with auto generated name
} else if (path.length > 1) { // since the path doesn't exist, we have been specified a specific name
String[] subPath = Arrays.copyOf(path, path.length - 1);
- getTree().select(subPath);
- getTree().contextChoose(ACTION_NEW_CONNECTION_TEXT);
+ selectAndContextChoose(subPath, ACTION_NEW_CONNECTION_TEXT);
finalPath = path;
connectionName = path[path.length - 1];
} else {
@@ -268,8 +266,7 @@ private String getDefaultConnectionName(String host, String port) {
public void createFolder(String ... path) {
if (path.length > 1) {
String[] subPath = Arrays.copyOf(path, path.length - 1);
- getTree().select(subPath);
- getTree().contextChoose(ACTION_NEW_FOLDER_TEXT);
+ selectAndContextChoose(subPath, ACTION_NEW_FOLDER_TEXT);
} else {
getToolBar().clickToolItem(ACTION_NEW_FOLDER_TOOLTIP);
}
@@ -321,8 +318,10 @@ public void deleteItem(String ... path) {
delete.clickButton(MCButton.Labels.YES);
waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(1000);
+ }
Assert.assertFalse("Failed deleting", itemExists(path));
- // Mac needs time to recover UI state after deletion before next operation
if (MCJemmyBase.isOSX()) {
sleep(500);
}
@@ -467,8 +466,22 @@ public MCDialog doubleClickRecording(String name) {
* @return a {@link MCDialog}
*/
public MCDialog doubleClickRecording(String name, String ... path) {
- getTree().selectAndClick(2, createRecordingPath(name, path));
- return MCDialog.getByAnyDialogTitle(false, DUMP_RECORDING_WIZARD_PAGE_TITLE);
+ int maxAttempts = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < maxAttempts; attempt++) {
+ getTree().selectAndClick(2, createRecordingPath(name, path));
+ waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(1000);
+ }
+ MCDialog dialog = MCDialog.getByAnyDialogTitle(true, DUMP_RECORDING_WIZARD_PAGE_TITLE);
+ if (dialog != null) {
+ System.out.println("[JvmBrowser] doubleClickRecording: dialog found on attempt " + (attempt + 1));
+ return dialog;
+ }
+ System.out.println("[JvmBrowser] doubleClickRecording: dialog not found on attempt " + (attempt + 1));
+ sleep(1000);
+ }
+ return MCDialog.getByAnyDialogTitle(true, DUMP_RECORDING_WIZARD_PAGE_TITLE);
}
/**
@@ -496,12 +509,20 @@ public MCDialog dumpRecording(String name, String ... path) {
}
private MCDialog doDumpRecording(String actionName, String ... path) {
- selectContextOption(actionName, path);
- waitForIdle();
- if (MCJemmyBase.isOSX()) {
+ int maxAttempts = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < maxAttempts; attempt++) {
+ selectContextOption(actionName, path);
+ waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(1000);
+ }
+ MCDialog dialog = MCDialog.getByAnyDialogTitle(true, DUMP_RECORDING_WIZARD_PAGE_TITLE);
+ if (dialog != null) {
+ return dialog;
+ }
sleep(1000);
}
- return MCDialog.getByAnyDialogTitle(false, DUMP_RECORDING_WIZARD_PAGE_TITLE);
+ return MCDialog.getByAnyDialogTitle(true, DUMP_RECORDING_WIZARD_PAGE_TITLE);
}
/**
@@ -525,7 +546,23 @@ public JfrWizard editRecording(String name) {
* @return a {@link JfrWizard}
*/
public JfrWizard editRecording(String name, String ... path) {
- selectContextOption(ACTION_EDIT_RECORDING_LABEL, createRecordingPath(name, path));
+ int maxAttempts = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < maxAttempts; attempt++) {
+ selectContextOption(ACTION_EDIT_RECORDING_LABEL, createRecordingPath(name, path));
+ waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(1000);
+ }
+ MCDialog dialog = MCDialog.getByAnyDialogTitle(true, JfrWizard.EDIT_RECORDING_WIZARD_PAGE_TITLE);
+ if (dialog != null) {
+ System.out.println("[JvmBrowser] editRecording: dialog found on attempt " + (attempt + 1));
+ return new JfrWizard(dialog);
+ }
+ System.out.println(
+ "[JvmBrowser] editRecording: dialog not found on attempt " + (attempt + 1) + ", retrying...");
+ sleep(1000);
+ }
+ System.out.println("[JvmBrowser] editRecording: falling back to direct constructor");
return new JfrWizard(JfrWizard.EDIT_RECORDING_WIZARD_PAGE_TITLE);
}
@@ -634,8 +671,22 @@ public void editConnection(
String name, String host, String port, String user, String serverPasswd, String mcPasswd, Boolean save,
String ... path) {
MCMenu.ensureJvmBrowserVisible();
- getTree().select(path);
- getTree().contextChoose(ACTION_EDIT_TEXT);
+ int retries = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ getTree().select(path);
+ waitForIdle();
+ int delay = MCJemmyBase.isOSX() ? 500 : MCJemmyBase.BETWEEN_KEYSTROKES_SLEEP;
+ sleep(delay);
+ try {
+ getTree().contextChoose(ACTION_EDIT_TEXT);
+ break;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
MCDialog properties = new MCDialog(DIALOG_CONNECTION_PROPERTIES_TITLE);
if (host != null) {
properties.enterText(ConnectionWizardPage.HOSTNAME_FIELD_NAME, host);
@@ -691,8 +742,22 @@ public void openPersistedJMXData() {
*/
public void openPersistedJMXData(String ... path) {
MCMenu.ensureJvmBrowserVisible();
- selectAction(TREE_ITEM_CONSOLE, path);
- getTree().contextChoose(ACTION_OPEN_PERSISTED_JMX_DATA);
+ int retries = MCJemmyBase.isOSX() ? 5 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ selectAction(TREE_ITEM_CONSOLE, path);
+ waitForIdle();
+ int delay = MCJemmyBase.isOSX() ? 500 : MCJemmyBase.BETWEEN_KEYSTROKES_SLEEP;
+ sleep(delay);
+ try {
+ getTree().contextChoose(ACTION_OPEN_PERSISTED_JMX_DATA);
+ break;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
Assert.assertTrue("Unable to find console editor \"Persisted JMX Data\"",
MCJemmyBase.waitForSubstringMatchedEditor("Persisted JMX Data"));
}
@@ -708,8 +773,22 @@ public void openPersistedJMXData(String ... path) {
public void renameFolder(String newName, String ... path) {
String[] finalPath = Arrays.copyOf(path, path.length);
finalPath[path.length - 1] = newName;
- getTree().select(path);
- getTree().contextChoose(ACTION_EDIT_TEXT);
+ int retries = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ getTree().select(path);
+ waitForIdle();
+ int delay = MCJemmyBase.isOSX() ? 500 : MCJemmyBase.BETWEEN_KEYSTROKES_SLEEP;
+ sleep(delay);
+ try {
+ getTree().contextChoose(ACTION_EDIT_TEXT);
+ break;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
MCDialog rename = new MCDialog(DIALOG_FOLDER_PROPERTIES_TITLE);
rename.replaceText(path[path.length - 1], newName);
rename.closeWithButton(MCButton.Labels.OK);
@@ -728,12 +807,22 @@ public void renameFolder(String newName, String ... path) {
*/
public void selectContextOption(String option, String ... path) {
MCMenu.ensureJvmBrowserVisible();
- getTree().select(path);
- waitForIdle();
- // Mac needs significantly more time for UI to stabilize after operations
- int delay = MCJemmyBase.isOSX() ? 500 : MCJemmyBase.BETWEEN_KEYSTROKES_SLEEP;
- sleep(delay);
- getTree().contextChoose(option);
+ int retries = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ getTree().select(path);
+ waitForIdle();
+ int delay = MCJemmyBase.isOSX() ? 500 : MCJemmyBase.BETWEEN_KEYSTROKES_SLEEP;
+ sleep(delay);
+ try {
+ getTree().contextChoose(option);
+ return;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
}
/**
@@ -779,8 +868,22 @@ public JfrWizard startFlightRecordingWizard(String ... path) {
*/
public JfrWizard startFlightRecordingWizard(boolean enableCommercialFeatures, String ... path) {
MCMenu.ensureJvmBrowserVisible();
- selectAction(TREE_ITEM_FLIGHTRECORDER, path);
- getTree().contextChoose(ACTION_START_FLIGHTRECORDER_LABEL);
+ int retries = MCJemmyBase.isOSX() ? 5 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ selectAction(TREE_ITEM_FLIGHTRECORDER, path);
+ waitForIdle();
+ int delay = MCJemmyBase.isOSX() ? 500 : MCJemmyBase.BETWEEN_KEYSTROKES_SLEEP;
+ sleep(delay);
+ try {
+ getTree().contextChoose(ACTION_START_FLIGHTRECORDER_LABEL);
+ break;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
if (enableCommercialFeatures) {
MCDialog dialog = new MCDialog(COMMERCIAL_FEATURES_QUESTION_TITLE);
dialog.closeWithButton(Labels.YES);
@@ -908,34 +1011,50 @@ private static void setTextByName(org.eclipse.swt.widgets.Composite parent, Stri
public void connect(boolean valid, String ... path) {
MCMenu.ensureJvmBrowserVisible();
String connectionName = path[path.length - 1];
- int retries = MCJemmyBase.isOSX() ? 5 : 1;
- for (int attempt = 0; attempt < retries; attempt++) {
- selectAction(TREE_ITEM_CONSOLE, path);
- waitForIdle();
- if (MCJemmyBase.isOSX()) {
- sleep(1000);
- }
- try {
- getTree().contextChoose(ACTION_START_CONSOLE_LABEL);
- break;
- } catch (RuntimeException e) {
- if (attempt == retries - 1) {
- throw e;
+ int connectAttempts = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int connectAttempt = 0; connectAttempt < connectAttempts; connectAttempt++) {
+ int retries = MCJemmyBase.isOSX() ? 5 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ selectAction(TREE_ITEM_CONSOLE, path);
+ waitForIdle();
+ if (MCJemmyBase.isOSX()) {
+ sleep(1000);
}
- sleep(1000);
- }
- }
- if (valid) {
- if (!ConnectionHelper.is7u40orLater(connectionName)) {
try {
- MCDialog dialog = new MCDialog(TOO_OLD_JVM_TITLE);
- dialog.closeWithButton(MCButton.Labels.OK);
- } catch (TimeoutExpiredException tee) {
- Assert.fail("JVM Too Old warning did not show.");
+ getTree().contextChoose(ACTION_START_CONSOLE_LABEL);
+ break;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
}
}
- Assert.assertTrue("Could not find JMX Console for connection \"" + connectionName + "\"",
- waitForSubstringMatchedEditor(connectionName));
+ if (valid) {
+ MCDialog errorDialog = MCDialog.getByAnyDialogTitle(false, false, "Problem", "Error", "Connection");
+ if (errorDialog != null) {
+ errorDialog.clickButton(Labels.OK);
+ waitForIdle();
+ }
+ if (!ConnectionHelper.is7u40orLater(connectionName)) {
+ try {
+ MCDialog dialog = new MCDialog(TOO_OLD_JVM_TITLE);
+ dialog.closeWithButton(MCButton.Labels.OK);
+ } catch (TimeoutExpiredException tee) {
+ Assert.fail("JVM Too Old warning did not show.");
+ }
+ }
+ long waitTime = (connectAttempt < connectAttempts - 1) ? 10000 : 30000;
+ boolean found = waitForSubstringMatchedEditor(waitTime, connectionName);
+ if (found) {
+ return;
+ }
+ if (connectAttempt >= connectAttempts - 1) {
+ Assert.fail("Could not find JMX Console for connection \"" + connectionName + "\"");
+ }
+ } else {
+ return;
+ }
}
}
@@ -1021,6 +1140,25 @@ private String[] createRecordingPath(String recordingName, String ... path) {
return completePath.toArray(new String[completePath.size()]);
}
+ private void selectAndContextChoose(String[] path, String menuItem) {
+ int retries = MCJemmyBase.isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ getTree().select(path);
+ waitForIdle();
+ int delay = MCJemmyBase.isOSX() ? 500 : MCJemmyBase.BETWEEN_KEYSTROKES_SLEEP;
+ sleep(delay);
+ try {
+ getTree().contextChoose(menuItem);
+ return;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
+ }
+
private void selectAction(String action, String ... path) {
String[] actionPath = Arrays.copyOf(path, path.length + 1);
actionPath[path.length] = action;
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCChartCanvas.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCChartCanvas.java
index c6a4ab4038..472ebd4851 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCChartCanvas.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCChartCanvas.java
@@ -105,13 +105,33 @@ public static MCChartCanvas getChartCanvas() {
*/
@SuppressWarnings("unchecked")
public void clickContextMenuItem(String menuItemText) {
- focusMc();
- StringPopupOwner contextMenu = control.as(StringPopupOwner.class);
- contextMenu.setPolicy(StringComparePolicy.SUBSTRING);
- contextMenu.push(getRelativeClickPoint(), new String[] {menuItemText});
- waitForIdle();
- if (isOSX()) {
- sleep(500);
+ int maxAttempts = isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < maxAttempts; attempt++) {
+ try {
+ focusMc();
+ if (isOSX()) {
+ sleep(300);
+ }
+ StringPopupOwner contextMenu = control.as(StringPopupOwner.class);
+ contextMenu.setPolicy(StringComparePolicy.SUBSTRING);
+ contextMenu.push(getRelativeClickPoint(), new String[] {menuItemText});
+ waitForIdle();
+ if (isOSX()) {
+ sleep(500);
+ }
+ System.out.println("[MCChartCanvas] clickContextMenuItem(\"" + menuItemText
+ + "\") succeeded on attempt " + (attempt + 1));
+ return;
+ } catch (RuntimeException e) {
+ System.out.println("[MCChartCanvas] clickContextMenuItem(\"" + menuItemText + "\") failed on attempt "
+ + (attempt + 1) + ": " + e.getMessage());
+ if (attempt == maxAttempts - 1) {
+ throw e;
+ }
+ // Press Escape to clear any stale menu state
+ control.keyboard().pushKey(KeyboardButtons.ESCAPE);
+ sleep(500);
+ }
}
}
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCDialog.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCDialog.java
index 0584dd51b3..8ab844204c 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCDialog.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCDialog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -82,7 +82,7 @@ public MCDialog(String dialogTitle) {
* @return a matching {@link MCDialog} or {@code null} if not found
*/
public static MCDialog getByAnyDialogTitle(boolean exactMatching, boolean waitForIdleUi, String ... dialogTitles) {
- int maxRetries = 10;
+ int maxRetries = waitForIdleUi ? 20 : 10;
MCDialog result = null;
while (result == null && maxRetries > 0) {
for (Wrap extends Shell> thisShell : getVisible(Shells.SHELLS.lookup(Shell.class), waitForIdleUi,
@@ -96,6 +96,9 @@ public static MCDialog getByAnyDialogTitle(boolean exactMatching, boolean waitFo
}
}
maxRetries--;
+ if (result == null && waitForIdleUi) {
+ sleep(200);
+ }
}
return result;
}
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTabFolder.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTabFolder.java
index cf9e413e41..465710cef9 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTabFolder.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTabFolder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -220,12 +220,35 @@ public void run() {
*/
@SuppressWarnings("unchecked")
public void closeAll() {
- ensureAlive();
- click();
- StringPopupOwner popupMenu = control.as(StringPopupOwner.class);
- Wrap extends CTabItem> item = control.as(Parent.class, CTabItem.class).lookup(CTabItem.class).wrap();
- popupMenu.setPolicy(policy);
- popupMenu.push(item.getClickPoint(), "Close All");
+ int retries = isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ try {
+ ensureAlive();
+ } catch (RuntimeException | AssertionError e) {
+ if (attempt == retries - 1) {
+ return;
+ }
+ sleep(500);
+ continue;
+ }
+ click();
+ waitForIdle();
+ if (isOSX()) {
+ sleep(500);
+ }
+ try {
+ StringPopupOwner popupMenu = control.as(StringPopupOwner.class);
+ Wrap extends CTabItem> item = control.as(Parent.class, CTabItem.class).lookup(CTabItem.class).wrap();
+ popupMenu.setPolicy(policy);
+ popupMenu.push(item.getClickPoint(), "Close All");
+ return;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
}
/**
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTree.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTree.java
index 5487089bd0..b098519fd2 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTree.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/MCTree.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
- *
+ *
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The contents of this file are subject to the terms of either the Universal Permissive License
@@ -10,17 +10,17 @@
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
- *
+ *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
- *
+ *
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
@@ -102,7 +102,7 @@ public static List getAll(Wrap extends Shell> shell) {
/**
* Returns all currently visible {@link MCTree} (in the main Mission Control Window)
- *
+ *
* @return a {@link List} of {@link MCTree} that were found
*/
public static List getAll() {
@@ -133,7 +133,7 @@ public static MCTree getFirstVisibleByName(String name) {
/**
* Finds the first visible Tree (in the main Mission Control Window)
- *
+ *
* @return a {@link MCTree}
*/
public static MCTree getFirst() {
@@ -142,7 +142,7 @@ public static MCTree getFirst() {
/**
* Finds the tree that contains a matching item
- *
+ *
* @param item
* the desired item text
* @return a {@link MCTree}
@@ -212,7 +212,7 @@ static MCTree getFirst(Wrap extends Shell> shell) {
/**
* Finds the first visible tree in the SWT hierarchy for the given shell
- *
+ *
* @param shell
* the shell from where to start searching for the widget
* @param waitForIdleUi
@@ -380,7 +380,7 @@ public void selectAndClick(int times, String ... path) {
/**
* Returns a list of the currently selected tree item's text values
- *
+ *
* @return a {@link List} of {@link String}
*/
public List getSelectedItemTexts() {
@@ -432,7 +432,7 @@ public void run() {
/**
* Get the currently selected item's direct child item texts
- *
+ *
* @return a {@link List} of {@link String}
*/
public List getSelectedItemChildrenTexts() {
@@ -779,10 +779,22 @@ private boolean makeVisibleInTreeByScrolling(ItemWrap itemWrap, Intege
*/
@SuppressWarnings("unchecked")
public void contextChoose(boolean desiredState, String ... choice) {
- scrollbarSafeSelection();
- StringPopupSelectableOwner spo = control.as(StringPopupSelectableOwner.class);
- spo.setPolicy(policy);
- spo.push(desiredState, getRelativeClickPoint(getSelectedItem()), choice);
+ int retries = isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ scrollbarSafeSelection();
+ try {
+ StringPopupSelectableOwner spo = control.as(StringPopupSelectableOwner.class);
+ spo.setPolicy(policy);
+ spo.push(desiredState, getRelativeClickPoint(getSelectedItem()), choice);
+ return;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ control.keyboard().pushKey(KeyboardButtons.ESCAPE);
+ sleep(500);
+ }
+ }
}
/**
@@ -809,15 +821,28 @@ public boolean getContextOptionState(String ... choice) {
*/
@SuppressWarnings("unchecked")
public void contextChoose(String ... choice) {
- scrollbarSafeSelection();
- Wrap extends TreeItem> selectedWrap = getSelectedItem();
- // workaround (needed on Mac OS X) to make sure that a yellow popup won't disturb during context clicking
- if (isOSX()) {
- selectedWrap.mouse().click();
+ int retries = isOSX() ? 3 : 1;
+ for (int attempt = 0; attempt < retries; attempt++) {
+ scrollbarSafeSelection();
+ Wrap extends TreeItem> selectedWrap = getSelectedItem();
+ if (isOSX()) {
+ selectedWrap.mouse().click();
+ waitForIdle();
+ sleep(200);
+ }
+ try {
+ StringPopupOwner spo = control.as(StringPopupOwner.class);
+ spo.setPolicy(policy);
+ spo.push(getRelativeClickPoint(selectedWrap), choice);
+ return;
+ } catch (RuntimeException e) {
+ if (attempt == retries - 1) {
+ throw e;
+ }
+ control.keyboard().pushKey(KeyboardButtons.ESCAPE);
+ sleep(500);
+ }
}
- StringPopupOwner spo = control.as(StringPopupOwner.class);
- spo.setPolicy(policy);
- spo.push(getRelativeClickPoint(selectedWrap), choice);
}
/**
@@ -891,33 +916,128 @@ public void run() {
/**
* Sets the text of the currently selected tree item
- *
+ *
* @param text
* the text to set
*/
public void enterText(String text) {
- int retries = isOSX() ? 3 : 1;
- for (int attempt = 0; attempt < retries; attempt++) {
- waitForIdle();
- if (isOSX()) {
- sleep(500);
- }
- try {
- contextChoose("Change Value");
- break;
- } catch (RuntimeException e) {
- if (attempt == retries - 1) {
- throw e;
+ if (isOSX()) {
+ enterTextMacOS(text);
+ } else {
+ enterTextDefault(text);
+ }
+ }
+
+ private void enterTextDefault(String text) {
+ waitForIdle();
+ contextChoose("Change Value");
+ waitForIdle();
+ typeText(text);
+ control.keyboard().pushKey(KeyboardButtons.ENTER);
+ }
+
+ private void enterTextMacOS(String text) {
+ // On macOS, cell editor activation via context menu is unreliable due to
+ // focus-stealing events. Set the attribute value directly on the model instead.
+ if (setAttributeValueDirectly(text)) {
+ return;
+ }
+ // Fallback: try context menu + typeText
+ waitForIdle();
+ sleep(500);
+ try {
+ contextChoose("Change Value");
+ } catch (RuntimeException e) {
+ sleep(1000);
+ contextChoose("Change Value");
+ }
+ waitForIdle();
+ sleep(500);
+ typeText(text);
+ control.keyboard().pushKey(KeyboardButtons.ENTER);
+ }
+
+ private boolean setAttributeValueDirectly(String text) {
+ Fetcher fetcher = new Fetcher() {
+ @Override
+ public void run() {
+ Tree tree = getWrap().getControl();
+ TreeItem[] selection = tree.getSelection();
+ if (selection == null || selection.length == 0) {
+ setOutput(false);
+ return;
}
- sleep(1000);
+ Object data = selection[0].getData();
+ if (data instanceof org.openjdk.jmc.rjmx.services.IAttribute) {
+ org.openjdk.jmc.rjmx.services.IAttribute attr = (org.openjdk.jmc.rjmx.services.IAttribute) data;
+ String typeName = attr.getInfo().getType();
+ // Skip array types - ArrayLengthCellEditor creates child model objects
+ // that direct setValue() cannot replicate
+ if (typeName != null && typeName.startsWith("[")) {
+ setOutput(false);
+ return;
+ }
+ Object typedValue = convertToType(text, typeName);
+ attr.setValue(typedValue);
+ // Refresh the viewer to reflect the change
+ Object viewerObj = tree.getData("org.eclipse.jface.viewer");
+ if (viewerObj == null) {
+ viewerObj = tree.getData("viewer");
+ }
+ if (viewerObj instanceof org.eclipse.jface.viewers.ColumnViewer) {
+ org.eclipse.jface.viewers.ColumnViewer cv = (org.eclipse.jface.viewers.ColumnViewer) viewerObj;
+ cv.refresh();
+ }
+ setOutput(true);
+ return;
+ }
+ setOutput(false);
}
+ };
+ Display.getDefault().syncExec(fetcher);
+ return Boolean.TRUE.equals(fetcher.getOutput());
+ }
+
+ private static Object convertToType(String text, String typeName) {
+ if (typeName == null) {
+ return text;
+ }
+ try {
+ switch (typeName) {
+ case "long":
+ case "java.lang.Long":
+ return Long.parseLong(text);
+ case "int":
+ case "java.lang.Integer":
+ return Integer.parseInt(text);
+ case "short":
+ case "java.lang.Short":
+ return Short.parseShort(text);
+ case "byte":
+ case "java.lang.Byte":
+ return Byte.parseByte(text);
+ case "double":
+ case "java.lang.Double":
+ return Double.parseDouble(text);
+ case "float":
+ case "java.lang.Float":
+ return Float.parseFloat(text);
+ case "boolean":
+ case "java.lang.Boolean":
+ return Boolean.parseBoolean(text);
+ default:
+ return text;
+ }
+ } catch (NumberFormatException e) {
+ return text;
}
+ }
+
+ private void typeText(String text) {
for (int i = 0; i < text.length(); i++) {
control.keyboard().typeChar(text.charAt(i));
sleep(BETWEEN_KEYSTROKES_SLEEP);
}
- // make sure that the text entered is "submitted" before moving focus elsewhere (necessary for Mac)
- control.keyboard().pushKey(KeyboardButtons.ENTER);
}
/**
diff --git a/core/org.openjdk.jmc.rjmx.common/src/main/java/org/openjdk/jmc/rjmx/common/ConnectionDecorator.java b/core/org.openjdk.jmc.rjmx.common/src/main/java/org/openjdk/jmc/rjmx/common/ConnectionDecorator.java
new file mode 100644
index 0000000000..9ef0a45ad1
--- /dev/null
+++ b/core/org.openjdk.jmc.rjmx.common/src/main/java/org/openjdk/jmc/rjmx/common/ConnectionDecorator.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at https://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.rjmx.common;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServerConnection;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+
+/**
+ * Simple decorator for inserting JMC specific handling to a server connection
+ */
+public class ConnectionDecorator implements MBeanServerConnection {
+
+ private final MBeanServerConnection delegate;
+
+ public ConnectionDecorator(final MBeanServerConnection delegate) {
+ this.delegate = delegate;
+ }
+
+ public ObjectInstance createMBean(String className, ObjectName name)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, IOException {
+ return delegate.createMBean(className, name);
+ }
+
+ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException, IOException {
+ return delegate.createMBean(className, name, loaderName);
+ }
+
+ public ObjectInstance createMBean(String className, ObjectName name, Object[] params, String[] signature)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, IOException {
+ return delegate.createMBean(className, name, params, signature);
+ }
+
+ public ObjectInstance createMBean(
+ String className, ObjectName name, ObjectName loaderName, Object[] params, String[] signature)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException, IOException {
+ return delegate.createMBean(className, name, loaderName, params, signature);
+ }
+
+ public void unregisterMBean(ObjectName name)
+ throws InstanceNotFoundException, MBeanRegistrationException, IOException {
+ delegate.unregisterMBean(name);
+ }
+
+ public ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException, IOException {
+ return delegate.getObjectInstance(name);
+ }
+
+ public Set queryMBeans(ObjectName name, QueryExp query) throws IOException {
+ return delegate.queryMBeans(name, query);
+ }
+
+ public Set queryNames(ObjectName name, QueryExp query) throws IOException {
+ return delegate.queryNames(name, query);
+ }
+
+ public boolean isRegistered(ObjectName name) throws IOException {
+ return delegate.isRegistered(name);
+ }
+
+ public Integer getMBeanCount() throws IOException {
+ return delegate.getMBeanCount();
+ }
+
+ public Object getAttribute(ObjectName name, String attribute) throws MBeanException, AttributeNotFoundException,
+ InstanceNotFoundException, ReflectionException, IOException {
+ return delegate.getAttribute(name, attribute);
+ }
+
+ public AttributeList getAttributes(ObjectName name, String[] attributes)
+ throws InstanceNotFoundException, ReflectionException, IOException {
+ return delegate.getAttributes(name, attributes);
+ }
+
+ public void setAttribute(ObjectName name, Attribute attribute)
+ throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException,
+ MBeanException, ReflectionException, IOException {
+ delegate.setAttribute(name, attribute);
+ }
+
+ public AttributeList setAttributes(ObjectName name, AttributeList attributes)
+ throws InstanceNotFoundException, ReflectionException, IOException {
+ return delegate.setAttributes(name, attributes);
+ }
+
+ public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature)
+ throws InstanceNotFoundException, MBeanException, ReflectionException, IOException {
+ return delegate.invoke(name, operationName, params, signature);
+ }
+
+ public String getDefaultDomain() throws IOException {
+ return delegate.getDefaultDomain();
+ }
+
+ public String[] getDomains() throws IOException {
+ return delegate.getDomains();
+ }
+
+ public void addNotificationListener(
+ ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, IOException {
+ delegate.addNotificationListener(name, listener, filter, handback);
+ }
+
+ public void addNotificationListener(
+ ObjectName name, ObjectName listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, IOException {
+ delegate.addNotificationListener(name, listener, filter, handback);
+ }
+
+ public void removeNotificationListener(ObjectName name, ObjectName listener)
+ throws InstanceNotFoundException, ListenerNotFoundException, IOException {
+ delegate.removeNotificationListener(name, listener);
+ }
+
+ public void removeNotificationListener(
+ ObjectName name, ObjectName listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException, IOException {
+ delegate.removeNotificationListener(name, listener, filter, handback);
+ }
+
+ public void removeNotificationListener(ObjectName name, NotificationListener listener)
+ throws InstanceNotFoundException, ListenerNotFoundException, IOException {
+ delegate.removeNotificationListener(name, listener);
+ }
+
+ public void removeNotificationListener(
+ ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException, IOException {
+ delegate.removeNotificationListener(name, listener, filter, handback);
+ }
+
+ public MBeanInfo getMBeanInfo(ObjectName name)
+ throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException {
+ return delegate.getMBeanInfo(name);
+ }
+
+ public boolean isInstanceOf(ObjectName name, String className) throws InstanceNotFoundException, IOException {
+ return delegate.isInstanceOf(name, className);
+ }
+
+}
diff --git a/core/pom.xml b/core/pom.xml
index f4f78f10b5..20ba671aa7 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -76,6 +76,7 @@
3.1.1
3.1.0
0.8.10
+ 3.6.1
4.13.2
@@ -409,6 +410,24 @@
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ ${build.helper.maven.version}
+
+
+ prepare-package
+
+ add-source
+
+
+
+ ${rootDir}/license
+
+
+
+
+
org.apache.maven.plugins
maven-source-plugin
diff --git a/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target b/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target
index ccb1f991c8..822f6c9208 100644
--- a/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target
+++ b/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target
@@ -45,9 +45,13 @@
-
-
-
+
+
+
+
+
+
+
diff --git a/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target b/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target
index 4e5d410fe8..c04a6c55e2 100644
--- a/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target
+++ b/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target
@@ -45,9 +45,14 @@
-
-
-
+
+
+
+
+
+
+
+
diff --git a/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target b/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target
index 45c1e7321a..4dae437229 100644
--- a/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target
+++ b/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target
@@ -45,9 +45,13 @@
-
-
-
+
+
+
+
+
+
+
diff --git a/releng/platform-definitions/platform-definition-2025-09/platform-definition-2025-09.target b/releng/platform-definitions/platform-definition-2025-09/platform-definition-2025-09.target
index 1348992bc2..d0259eb22c 100644
--- a/releng/platform-definitions/platform-definition-2025-09/platform-definition-2025-09.target
+++ b/releng/platform-definitions/platform-definition-2025-09/platform-definition-2025-09.target
@@ -44,9 +44,13 @@
-
-
-
+
+
+
+
+
+
+
diff --git a/releng/third-party/pom.xml b/releng/third-party/pom.xml
index 01dfeba4a7..e9b2e78a21 100644
--- a/releng/third-party/pom.xml
+++ b/releng/third-party/pom.xml
@@ -61,7 +61,7 @@
2.0.0
12.1.0
1.3.7
- 2.4.2
+ 2.5.1
2.27.2
0.0.1-rc.9
8.5.0
@@ -166,14 +166,20 @@
org.jolokia:jolokia-service-discovery:${jolokia.version}
- true
-
- org.jolokia.service.discovery
-
+
+ org.jolokia:jolokia-service-serializer:${jolokia.version}
+
+
+ org.jolokia:jolokia-core:${jolokia.version}
+
org.jolokia:jolokia-server-core:${jolokia.version}
+
+ org.jolokia:jolokia-client-java:${jolokia.version}
+ false
+
org.osgi:org.osgi.service.servlet:2.0.0
diff --git a/scripts/checkcopyrightyear.sh b/scripts/checkcopyrightyear.sh
index c2d27a36dd..d10a0d4313 100755
--- a/scripts/checkcopyrightyear.sh
+++ b/scripts/checkcopyrightyear.sh
@@ -5,7 +5,9 @@ git remote -v | grep -w upstream || git remote add upstream https://github.com/o
git fetch upstream
CURRENT_YEAR=$(date +'%Y')
-MODIFIED_FILES=$(git diff --name-only upstream/master)
+COMMITTED_FILES=$(git diff --name-only --diff-filter=d upstream/master...HEAD)
+UNCOMMITTED_FILES=$(git diff --name-only --diff-filter=d)
+MODIFIED_FILES=$(echo -e "$COMMITTED_FILES\n$UNCOMMITTED_FILES" | sort -u | grep -v '^$')
counter=0
for fileToCheck in $MODIFIED_FILES