From b29c3caa0139bb62b30b0df0a6718645d98b4c4f Mon Sep 17 00:00:00 2001 From: Marcus Hirt Date: Wed, 25 Mar 2026 18:03:44 +0000 Subject: [PATCH 1/5] 8551: Stabilize UI tests on Mac Reviewed-by: aptmac --- .gitignore | 3 + .../uitest/DiagnosticCommandsTabTest.java | 72 +++++- .../uitest/JfrThreadsPageLegacyTest.java | 14 +- .../jemmy/misc/base/wrappers/MCJemmyBase.java | 11 +- .../test/jemmy/misc/wrappers/JfrWizard.java | 14 +- .../test/jemmy/misc/wrappers/JvmBrowser.java | 242 ++++++++++++++---- .../jemmy/misc/wrappers/MCChartCanvas.java | 34 ++- .../test/jemmy/misc/wrappers/MCDialog.java | 7 +- .../test/jemmy/misc/wrappers/MCTabFolder.java | 37 ++- .../jmc/test/jemmy/misc/wrappers/MCTree.java | 198 +++++++++++--- 10 files changed, 506 insertions(+), 126 deletions(-) diff --git a/.gitignore b/.gitignore index e009c5103..82f075751 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/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 e004ff9bc..8e0ba03ff 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 d7650b24c..a32acbc25 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 b7134f03a..b6a396a03 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 65126c911..fda61d023 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 d400f3d2d..f66f641f1 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 c6a4ab403..472ebd485 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 0584dd51b..8ab844204 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 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 cf9e413e4..465710cef 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 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 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 5487089bd..b098519fd 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 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 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 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 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); } /** From e83d2e895caf60583318972d686e3ef5b71eaa4a Mon Sep 17 00:00:00 2001 From: Alex Macdonald Date: Wed, 25 Mar 2026 18:06:22 +0000 Subject: [PATCH 2/5] 8554: Fix copyright year check script Reviewed-by: hirt --- scripts/checkcopyrightyear.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/checkcopyrightyear.sh b/scripts/checkcopyrightyear.sh index c2d27a36d..d10a0d431 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 From 151a108b27df538adbb39cdeaa553ebcad3d9476 Mon Sep 17 00:00:00 2001 From: Aymane Harmaz Date: Wed, 25 Mar 2026 18:57:23 +0000 Subject: [PATCH 3/5] 8536: Add files under core/license to sources jars of jmc/core submodules Reviewed-by: hirt --- core/pom.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/pom.xml b/core/pom.xml index f4f78f10b..20ba671aa 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 From a3b850a59c3439b71704ddb2c3d2a4898cd43150 Mon Sep 17 00:00:00 2001 From: Martin Skarsaune Date: Wed, 25 Mar 2026 19:58:49 +0000 Subject: [PATCH 4/5] 8545: Update Jolokia third party to 2.5.1 Reviewed-by: aptmac --- .../org.openjdk.jmc.feature.core/feature.xml | 9 +- .../META-INF/MANIFEST.MF | 9 +- .../jmc/jolokia/JmcJolokiaContext.java | 115 ++++++++++ .../jmc/jolokia/JmcJolokiaJmxConnection.java | 38 ++-- .../jmc/jolokia/JmcJolokiaJmxConnector.java | 20 +- .../openjdk/jmc/jolokia/JmcJolokiaPlugin.java | 20 +- .../META-INF/MANIFEST.MF | 3 + .../org.openjdk.jmc.jolokia.test/pom.xml | 6 +- .../org/openjdk/jmc/jolokia/JolokiaTest.java | 35 ++-- .../jmc/rjmx/common/ConnectionDecorator.java | 196 ++++++++++++++++++ .../platform-definition-2024-12.target | 10 +- .../platform-definition-2025-03.target | 11 +- .../platform-definition-2025-06.target | 10 +- .../platform-definition-2025-09.target | 10 +- releng/third-party/pom.xml | 16 +- 15 files changed, 422 insertions(+), 86 deletions(-) create mode 100644 application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaContext.java create mode 100644 core/org.openjdk.jmc.rjmx.common/src/main/java/org/openjdk/jmc/rjmx/common/ConnectionDecorator.java diff --git a/application/org.openjdk.jmc.feature.core/feature.xml b/application/org.openjdk.jmc.feature.core/feature.xml index 1135edbb9..e13b98c47 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 6ce14ce39..69d3a8f50 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 13b93bf5e..566be1e27 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 47e2e9bb1..5489d7035 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 ad701f71c..beeba2051 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 530cee570..7fea70e3e 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/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 000000000..9ef0a45ad --- /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/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 ccb1f991c..822f6c920 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 4e5d410fe..c04a6c55e 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 45c1e7321..4dae43722 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 1348992bc..d0259eb22 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 01dfeba4a..e9b2e78a2 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 From bde624e3c02f01d0da69af491f3f89e064188be4 Mon Sep 17 00:00:00 2001 From: Suchita Chaturvedi Date: Thu, 26 Mar 2026 14:26:40 +0000 Subject: [PATCH 5/5] 5561: Support for Crypto Events in JMC Reviewed-by: hirt --- ...D-0352E76D-96F5-4EDA-A8DE-88B9E18635B9.htm | 8 +- ...D-63742D06-CF58-47F2-9CF2-08C0DB9F09F1.htm | 8 +- .../html/SecurityPage.htm | 93 +++++ application/org.openjdk.jmc.docs/html/toc.htm | 3 +- application/org.openjdk.jmc.docs/toc.xml | 4 +- .../defaultPages.xml | 26 +- .../icons/pages/security16.png | Bin 0 -> 1324 bytes ...openjdk.jmc.flightrecorder.ui_contexts.xml | 7 +- .../plugin.xml | 4 + .../ui/common/ImageConstants.java | 3 +- .../flightrecorder/ui/common/ItemList.java | 18 +- .../ui/messages/internal/Messages.java | 5 + .../flightrecorder/ui/pages/SecurityPage.java | 389 ++++++++++++++++++ .../ui/messages/internal/messages.properties | 6 + .../icons/crypto_action.svg | 5 + .../icons/crypto_attention.svg | 5 + .../org.openjdk.jmc.ui/icons/crypto_ok.svg | 4 + .../java/org/openjdk/jmc/ui/UIPlugin.java | 13 +- .../openjdk/jmc/common/item/Aggregators.java | 6 +- .../common/messages/internal/Messages.java | 19 +- .../jmc/common/security/CryptoUtil.java | 280 +++++++++++++ .../messages/internal/messages.properties | 19 +- .../rules/jdk/general/CryptoSecurityRule.java | 278 +++++++++++++ .../rules/jdk/messages/internal/Messages.java | 11 +- ...org.openjdk.jmc.flightrecorder.rules.IRule | 3 +- .../jdk/messages/internal/messages.properties | 11 +- .../jmc/flightrecorder/rules/IRule.java | 2 +- .../rules/util/JfrRuleTopics.java | 3 +- .../rules/util/RulesToolkit.java | 8 +- .../flightrecorder/jdk/JdkAggregators.java | 8 +- .../jmc/flightrecorder/jdk/JdkAttributes.java | 180 +++++++- .../jmc/flightrecorder/jdk/JdkFilters.java | 3 +- .../jmc/flightrecorder/jdk/JdkTypeIDs.java | 4 +- .../jdk/messages/internal/Messages.java | 16 +- .../synthetic/OracleJdkTypeIDsPre11.java | 6 +- .../jdk/messages/internal/messages.properties | 16 +- .../resources/baseline/JfrRuleBaseline.xml | 92 +++++ 37 files changed, 1534 insertions(+), 32 deletions(-) create mode 100644 application/org.openjdk.jmc.docs/html/SecurityPage.htm create mode 100644 application/org.openjdk.jmc.flightrecorder.ui/icons/pages/security16.png create mode 100644 application/org.openjdk.jmc.flightrecorder.ui/src/main/java/org/openjdk/jmc/flightrecorder/ui/pages/SecurityPage.java create mode 100644 application/org.openjdk.jmc.ui/icons/crypto_action.svg create mode 100644 application/org.openjdk.jmc.ui/icons/crypto_attention.svg create mode 100644 application/org.openjdk.jmc.ui/icons/crypto_ok.svg create mode 100644 core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/security/CryptoUtil.java create mode 100644 core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/general/CryptoSecurityRule.java diff --git a/application/org.openjdk.jmc.docs/html/GUID-0352E76D-96F5-4EDA-A8DE-88B9E18635B9.htm b/application/org.openjdk.jmc.docs/html/GUID-0352E76D-96F5-4EDA-A8DE-88B9E18635B9.htm index 25cd6720d..c6032f2b7 100644 --- a/application/org.openjdk.jmc.docs/html/GUID-0352E76D-96F5-4EDA-A8DE-88B9E18635B9.htm +++ b/application/org.openjdk.jmc.docs/html/GUID-0352E76D-96F5-4EDA-A8DE-88B9E18635B9.htm @@ -1,7 +1,7 @@ @@ -24,7 +24,7 @@ - + @@ -39,7 +39,7 @@
- + Next
Next
@@ -115,7 +115,7 @@

Using the

- + Next
Next
diff --git a/application/org.openjdk.jmc.docs/html/GUID-63742D06-CF58-47F2-9CF2-08C0DB9F09F1.htm b/application/org.openjdk.jmc.docs/html/GUID-63742D06-CF58-47F2-9CF2-08C0DB9F09F1.htm index 674e9889c..02f3f7408 100644 --- a/application/org.openjdk.jmc.docs/html/GUID-63742D06-CF58-47F2-9CF2-08C0DB9F09F1.htm +++ b/application/org.openjdk.jmc.docs/html/GUID-63742D06-CF58-47F2-9CF2-08C0DB9F09F1.htm @@ -1,7 +1,7 @@ @@ -23,7 +23,7 @@ - + @@ -33,7 +33,7 @@
- + Previous
Previous
@@ -72,7 +72,7 @@

Using the

- + Previous
Previous
diff --git a/application/org.openjdk.jmc.docs/html/SecurityPage.htm b/application/org.openjdk.jmc.docs/html/SecurityPage.htm new file mode 100644 index 000000000..239738446 --- /dev/null +++ b/application/org.openjdk.jmc.docs/html/SecurityPage.htm @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + +Using the Security Page + + + + + + + + + + + + + + + + + + + + + +
+ +Previous
+Previous +
+
+ +Next
+Next +
+
+ +
+

Using the Security Page

+

The security page is designed to display information related to certificates used. It mainly displays the information derived from X509Certificate events.

+

There is one table which shows information related to the cryptographic algorithm. For example: Signature Algorithm, Key type, Key length, Certificate Valid from, Certificate expiring on, Certificate Id and Issuer details.

+

We have also added a new column Crypto Remark which will help customer to identify the action/attention item. Action and attention items are decided based on the JDK guidelines for Crypto usages.

+
Examples of Action and attention items:
  • Action Required. The Certificate has expired before 1,822 days. It should be replaced.
  • +
  • Attention Needed. SHA-1 signature. It should be updated to use SHA-256 or SHA-512.
  • +
+
+

Certificates with no issues are marked with an OK status in the Crypto Remark column.

+

There is one chart where we are displaying the occurrences of X509Certificate events with respect to the timeline.

+
+ +
+ + + + + + + + + + + +

+
+ +Previous
+Previous +
+
+ +Next
+Next +
+
+ + + + diff --git a/application/org.openjdk.jmc.docs/html/toc.htm b/application/org.openjdk.jmc.docs/html/toc.htm index afb7e67a6..e39810f23 100644 --- a/application/org.openjdk.jmc.docs/html/toc.htm +++ b/application/org.openjdk.jmc.docs/html/toc.htm @@ -1,7 +1,7 @@ @@ -134,6 +134,7 @@

Using the Socket I/O Page
  • Using the Method Profiling Page
  • Using the Exceptions and Errors Page
  • +
  • Using the Security Page
  • Using the Thread Dumps Page
  • diff --git a/application/org.openjdk.jmc.docs/toc.xml b/application/org.openjdk.jmc.docs/toc.xml index b545f57ff..a71239f5e 100644 --- a/application/org.openjdk.jmc.docs/toc.xml +++ b/application/org.openjdk.jmc.docs/toc.xml @@ -1,6 +1,6 @@