diff --git a/application/coverage/pom.xml b/application/coverage/pom.xml
index c38b20e649..810dd49e75 100644
--- a/application/coverage/pom.xml
+++ b/application/coverage/pom.xml
@@ -1,7 +1,7 @@
+
+
+
+
+
+
+
+
+
diff --git a/application/org.openjdk.jmc.jolokia/META-INF/MANIFEST.MF b/application/org.openjdk.jmc.jolokia/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..3f5a53aec2
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name
+Bundle-SymbolicName: org.openjdk.jmc.jolokia;singleton:=true
+Bundle-Version: 9.1.0.qualifier
+Automatic-Module-Name: org.openjdk.jmc.jolokia
+Bundle-RequiredExecutionEnvironment: JavaSE-17
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.ui,
+ org.jolokia.client-jmx-adapter.standalone;bundle-version="2.0.2";visibility:=reexport,
+ org.openjdk.jmc.common,
+ org.openjdk.jmc.rjmx,
+ org.openjdk.jmc.ui
+Export-Package: org.openjdk.jmc.jolokia,
+ org.openjdk.jmc.jolokia.preferences
+Bundle-Activator: org.openjdk.jmc.jolokia.JmcJolokiaPlugin
+Bundle-ActivationPolicy: lazy
diff --git a/application/org.openjdk.jmc.jolokia/OSGI-INF/l10n/bundle.properties b/application/org.openjdk.jmc.jolokia/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 0000000000..11d361ea1b
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,3 @@
+#Properties file for org.openjdk.jmc.jolokia
+page.name = Jolokia
+Bundle-Name = Jolokia JMC Connection
\ No newline at end of file
diff --git a/application/org.openjdk.jmc.jolokia/build.properties b/application/org.openjdk.jmc.jolokia/build.properties
new file mode 100644
index 0000000000..066b0f86b5
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/build.properties
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024, Kantega AS. 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 http://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.
+source.. = src/main/java/
+output.. = target/classes/
+bin.includes = META-INF/,\
+ OSGI-INF/,\
+ .,\
+ plugin.xml,\
+ OSGI-INF/l10n/bundle.properties
diff --git a/application/org.openjdk.jmc.jolokia/plugin.xml b/application/org.openjdk.jmc.jolokia/plugin.xml
new file mode 100644
index 0000000000..6fd9d09af4
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/plugin.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/application/org.openjdk.jmc.jolokia/pom.xml b/application/org.openjdk.jmc.jolokia/pom.xml
new file mode 100644
index 0000000000..c470d9a013
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/pom.xml
@@ -0,0 +1,49 @@
+
+
+
+ 4.0.0
+
+ org.openjdk.jmc
+ missioncontrol.application
+ ${revision}${changelist}
+
+ org.openjdk.jmc.jolokia
+ eclipse-plugin
+
+ ${project.basedir}/../../configuration
+
+
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
new file mode 100644
index 0000000000..1b53d7bc0e
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnection.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Kantega AS. 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 http://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.jolokia;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.LinkedList;
+import java.util.Optional;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.Descriptor;
+import javax.management.ImmutableDescriptor;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.ObjectName;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.TabularData;
+
+import org.jolokia.client.J4pClient;
+import org.jolokia.client.jmxadapter.RemoteJmxAdapter;
+import org.jolokia.service.serializer.JolokiaSerializer;
+import org.jolokia.server.core.service.serializer.SerializeOptions;
+
+/**
+ * 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 {
+
+ private static final String UNKNOWN = "Unknown"; //$NON-NLS-1$
+ private static final String DIAGNOSTIC_OPTIONS = "com.sun.management:type=DiagnosticCommand"; //$NON-NLS-1$
+ private static final String PREFIX = "dcmd."; //$NON-NLS-1$
+ private static final String IMPACT = PREFIX + "vmImpact"; //$NON-NLS-1$
+ private static final String NAME = PREFIX + "name"; //$NON-NLS-1$
+ private static final String DESCRIPTION = PREFIX + "description"; //$NON-NLS-1$
+ private static final String ARGUMENTS = PREFIX + "arguments"; //$NON-NLS-1$
+ private static final String ARGUMENT_NAME = PREFIX + "arg.name"; //$NON-NLS-1$
+ private static final String ARGUMENT_DESCRIPTION = PREFIX + "arg.description"; //$NON-NLS-1$
+ private static final String ARGUMENT_MANDATORY = PREFIX + "arg.isMandatory"; //$NON-NLS-1$
+ 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$
+
+ public JmcJolokiaJmxConnection(J4pClient client) throws IOException {
+ super(client);
+ }
+
+ @Override
+ public MBeanInfo getMBeanInfo(ObjectName name) throws InstanceNotFoundException, IOException {
+ MBeanInfo mBeanInfo = super.getMBeanInfo(name);
+ // the diagnostic options tab and memory relies on descriptor info in MBeanInfo,
+ // modify descriptors the first time
+ if (DIAGNOSTIC_OPTIONS.equals(name.getCanonicalName())
+ && mBeanInfo.getOperations()[0].getDescriptor() == ImmutableDescriptor.EMPTY_DESCRIPTOR) {
+
+ MBeanOperationInfo[] modifiedOperations = new MBeanOperationInfo[mBeanInfo.getOperations().length];
+
+ for (int i = 0; i < mBeanInfo.getOperations().length; i++) {
+ modifiedOperations[i] = stealOrBuildOperationInfo(mBeanInfo.getOperations()[i],
+ checkForLocalOperationInfo(name));
+ }
+ //create a copy with modified operations in place of the original MBeanInfo in the cache
+ final MBeanInfo modifiedMBeanInfo = new MBeanInfo(mBeanInfo.getClassName(), mBeanInfo.getDescription(),
+ mBeanInfo.getAttributes(), mBeanInfo.getConstructors(), modifiedOperations,
+ mBeanInfo.getNotifications());
+ this.mbeanInfoCache.put(name, modifiedMBeanInfo);
+ return modifiedMBeanInfo;
+ }
+ return mBeanInfo;
+ }
+
+ private Optional checkForLocalOperationInfo(ObjectName name) {
+ MBeanInfo localInfo;
+ try {
+ localInfo = ManagementFactory.getPlatformMBeanServer().getMBeanInfo(name);
+ } catch (Exception | NoClassDefFoundError ignore) {
+ localInfo = null;
+ }
+ return Optional.ofNullable(localInfo);
+ }
+
+ @Override
+ public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature)
+ throws InstanceNotFoundException, MBeanException, IOException {
+
+ if (params != null) {
+ for (int i = 0; i < params.length; i++) {
+ Object object = params[i];
+ if (object instanceof TabularData) {
+ try {
+ params[i] = new JolokiaSerializer().serialize(object, new LinkedList(),
+ SerializeOptions.DEFAULT);
+ } catch (AttributeNotFoundException ignore) {
+ }
+ }
+
+ }
+ }
+ return super.invoke(name, operationName, params, signature);
+ }
+
+ /**
+ * Build MBeanOperationInfo by taking information from the corresponding MBean in the local JVM
+ * for a more precise signature. If it is not available locally, attempt to construct it from
+ * the metadata from Jolokia.
+ *
+ * @param original
+ * MBeanInfo from Jolokia list.
+ * @param localInfo
+ * MBeanInfo from this JVM to use for getting descriptor.
+ * @return Descriptor
+ */
+ private MBeanOperationInfo stealOrBuildOperationInfo(MBeanOperationInfo original, Optional localInfo) {
+ return localInfo.map(info -> checkForMatchingLocalOperation(original, info))// first attempt to get descriptor from local copy
+ .orElseGet(() -> reverseEngineerOperationInfo(original));// if not, reverse engineer descriptor from operation info
+ }
+
+ private MBeanOperationInfo checkForMatchingLocalOperation(MBeanOperationInfo original, MBeanInfo info) {
+ for (MBeanOperationInfo localOperation : info.getOperations()) {
+ if (localOperation.getName().equals(original.getName())) {
+ if (localOperation.getSignature().length == original.getSignature().length) {
+ for (int i = 0; i < original.getSignature().length; i++) {
+ MBeanParameterInfo param = original.getSignature()[i];
+ if (!param.getType().equals(localOperation.getSignature()[i].getType())) {
+ break;
+ } else if (i == original.getSignature().length - 1) {
+ // whole signature matches, use as replacement
+ return localOperation;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private MBeanOperationInfo reverseEngineerOperationInfo(MBeanOperationInfo original) {
+ DescriptorSupport result = new DescriptorSupport();
+ result.setField(NAME, original.getName());
+ result.setField(DESCRIPTION, original.getDescription());
+ result.setField(IMPACT, UNKNOWN);
+ result.setField(ARGUMENTS, buildArguments(original.getSignature()));
+ return new MBeanOperationInfo(original.getName(), original.getDescription(), original.getSignature(),
+ original.getReturnType(), MBeanOperationInfo.UNKNOWN, result);
+ }
+
+ private Descriptor buildArguments(MBeanParameterInfo[] signature) {
+ DescriptorSupport parameters = new DescriptorSupport();
+ for (MBeanParameterInfo parameter : signature) {
+ parameters.setField(parameter.getName(), buildArgument(parameter));
+ }
+ return parameters;
+ }
+
+ private Descriptor buildArgument(MBeanParameterInfo parameter) {
+ DescriptorSupport result = new DescriptorSupport();
+ result.setField(ARGUMENT_NAME, parameter.getName());
+ boolean isMultiple = parameter.getType().startsWith("["); //$NON-NLS-1$
+ result.setField(ARGUMENT_MULITPLE, String.valueOf(isMultiple));
+ String type = parameter.getType();
+ if (isMultiple) {
+ if (type.startsWith("[L")) { //$NON-NLS-1$
+ type = type.substring(2);
+ } else {
+ type = type.substring(1);
+ }
+
+ }
+ // probably more reverse mapping of types should be done here, but we hope it is
+ // sufficient
+ result.setField(ARGUMENT_TYPE, type);
+ result.setField(ARGUMENT_DESCRIPTION, parameter.getDescription());
+ result.setField(ARGUMENT_MANDATORY, "false"); //$NON-NLS-1$
+ result.setField(ARGUMENT_OPTION, "false"); //$NON-NLS-1$
+ return result;
+ }
+
+ @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 {
+ return super.isInstanceOf(objectName, type);
+ } catch (NoClassDefFoundError | UnsatisfiedLinkError 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/JmcJolokiaJmxConnectionProvider.java b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnectionProvider.java
new file mode 100644
index 0000000000..271e81f318
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnectionProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Kantega AS. 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 http://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.jolokia;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorProvider;
+import javax.management.remote.JMXServiceURL;
+
+public class JmcJolokiaJmxConnectionProvider implements JMXConnectorProvider {
+ @Override
+ public JMXConnector newJMXConnector(JMXServiceURL serviceURL, Map environment) throws IOException {
+ if (!"jolokia".equals(serviceURL.getProtocol())) { //$NON-NLS-1$
+ throw new MalformedURLException(Messages
+ .getString("JmcJolokiaJmxConnectionProvider.JMC_JOLOKIA_JMX_CONNECTION_PROVIDER_EXCEPTION_MSG")); //$NON-NLS-1$
+ }
+ return new JmcJolokiaJmxConnector(serviceURL, environment);
+ }
+}
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
new file mode 100644
index 0000000000..07b1506a7b
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaJmxConnector.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Kantega AS. 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 http://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.jolokia;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.management.remote.JMXServiceURL;
+
+import org.jolokia.client.J4pClientBuilder;
+import org.jolokia.client.jmxadapter.JolokiaJmxConnector;
+import org.jolokia.client.jmxadapter.RemoteJmxAdapter;
+
+public class JmcJolokiaJmxConnector extends JolokiaJmxConnector {
+
+ public JmcJolokiaJmxConnector(JMXServiceURL serviceURL, Map environment) {
+ super(serviceURL, environment);
+ }
+
+ @Override
+ protected RemoteJmxAdapter instantiateAdapter(J4pClientBuilder clientBuilder, Map mergedEnv)
+ throws IOException {
+ return new JmcJolokiaJmxConnection(clientBuilder.build());
+ }
+}
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
new file mode 100644
index 0000000000..9b91a60e60
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/JmcJolokiaPlugin.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Kantega AS. 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 http://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.jolokia;
+
+import org.openjdk.jmc.ui.MCAbstractUIPlugin;
+
+public class JmcJolokiaPlugin extends MCAbstractUIPlugin {
+
+ public final static String PLUGIN_ID = "org.openjdk.jmc.jolokia"; //$NON-NLS-1$
+ private static JmcJolokiaPlugin plugin;
+
+ public JmcJolokiaPlugin() {
+ super(PLUGIN_ID);
+ plugin = this;
+ }
+
+ public static JmcJolokiaPlugin getDefault() {
+ return plugin;
+ }
+}
diff --git a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/Messages.java b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/Messages.java
new file mode 100644
index 0000000000..39cff0804c
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/Messages.java
@@ -0,0 +1,21 @@
+package org.openjdk.jmc.jolokia;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+ private static final String BUNDLE_NAME = Messages.class.getPackageName() + ".messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/messages.properties b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/messages.properties
new file mode 100644
index 0000000000..c0628eb037
--- /dev/null
+++ b/application/org.openjdk.jmc.jolokia/src/main/java/org/openjdk/jmc/jolokia/messages.properties
@@ -0,0 +1 @@
+JmcJolokiaJmxConnectionProvider.JMC_JOLOKIA_JMX_CONNECTION_PROVIDER_EXCEPTION_MSG=I only serve Jolokia connections
diff --git a/application/org.openjdk.jmc.rjmx/META-INF/MANIFEST.MF b/application/org.openjdk.jmc.rjmx/META-INF/MANIFEST.MF
index 8f029e6111..008845df05 100644
--- a/application/org.openjdk.jmc.rjmx/META-INF/MANIFEST.MF
+++ b/application/org.openjdk.jmc.rjmx/META-INF/MANIFEST.MF
@@ -16,7 +16,7 @@ Export-Package: org.openjdk.jmc.rjmx,
org.openjdk.jmc.flightrecorder.controlpanel.ui,
org.openjdk.jmc.browser",
org.openjdk.jmc.rjmx.actionprovider.internal;x-internal:=true,
- org.openjdk.jmc.rjmx.descriptorprovider;x-friends:="org.openjdk.jmc.browser.jdp,org.openjdk.jmc.browser.attach",
+ org.openjdk.jmc.rjmx.descriptorprovider;x-friends:="org.openjdk.jmc.browser.jdp,org.openjdk.jmc.browser.attach,org.openjdk.jmc.jolokia",
org.openjdk.jmc.rjmx.internal;
x-friends:="org.openjdk.jmc.browser,
org.openjdk.jmc.console.ui.mbeanbrowser,
diff --git a/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/internal/ProtocolInitializer.java b/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/internal/ProtocolInitializer.java
new file mode 100644
index 0000000000..4f808a805c
--- /dev/null
+++ b/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/internal/ProtocolInitializer.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Red Hat Inc. 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 http://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.internal;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.logging.Level;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorProvider;
+import javax.management.remote.JMXServiceURL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.openjdk.jmc.rjmx.RJMXPlugin;
+
+public class ProtocolInitializer {
+ private final static String EXTENSION_POINT = "org.openjdk.jmc.rjmx.jmxProtocols";//$NON-NLS-1$
+ private final static String EXTENSION_ELEMENT_CLIENT = "client";//$NON-NLS-1$
+ private final static String EXTENSION_ATTRIBUTE_CLASS = "class";//$NON-NLS-1$
+ private final static String EXTENSION_ATTRIBUTE_PROTOCOL = "protocol";//$NON-NLS-1$
+ private final static String ATTRIBUTE_KEY = "name"; //$NON-NLS-1$
+ private final static String TAG_SYSPROPERTY = "sysproperty"; //$NON-NLS-1$
+ private final static String ATTRIBUTE_INCLUDE = "include"; //$NON-NLS-1$
+ private final static String ATTRIBUTE_SEPARATOR = "separator"; //$NON-NLS-1$
+
+ public JMXConnector newJMXConnector(JMXServiceURL serviceURL, Map environment) throws IOException {
+ JMXConnectorProvider realProvider = findProtocolExtension(serviceURL);
+ if (realProvider == null) {
+ return null;
+ }
+ return realProvider.newJMXConnector(serviceURL, environment);
+ }
+
+ public JMXConnectorProvider findProtocolExtension(JMXServiceURL serviceURL) {
+ try {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ for (IConfigurationElement config : registry.getConfigurationElementsFor(EXTENSION_POINT)) {
+ if (config.getName().equals(EXTENSION_ELEMENT_CLIENT)) {
+ final String protocol = config.getAttribute(EXTENSION_ATTRIBUTE_PROTOCOL);
+ if (serviceURL.getProtocol().equals(protocol)) {
+ JMXConnectorProvider provider = (JMXConnectorProvider) config
+ .createExecutableExtension(EXTENSION_ATTRIBUTE_CLASS);
+ for (IConfigurationElement prop : config.getChildren(TAG_SYSPROPERTY)) {
+ ensureSystemProperty(prop.getAttribute(ATTRIBUTE_KEY), prop.getAttribute(ATTRIBUTE_INCLUDE),
+ prop.getAttribute(ATTRIBUTE_SEPARATOR));
+ }
+ return provider;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ RJMXPlugin.getDefault().getLogger().log(Level.SEVERE, "Could not instantiate JMX protocol provider!", e);
+ }
+ return null;
+ }
+
+ private static void ensureSystemProperty(String key, String include, String separator) {
+ String org = System.getProperty(key);
+ if (org == null) {
+ System.setProperty(key, include);
+ return;
+ }
+ if ((separator + org + separator).indexOf(separator + include + separator) < 0) {
+ System.setProperty(key, org + separator + include);
+ }
+ }
+}
diff --git a/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/internal/ServerHandle.java b/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/internal/ServerHandle.java
index 83eebb82d2..19dd1800ba 100644
--- a/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/internal/ServerHandle.java
+++ b/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/internal/ServerHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -32,12 +32,17 @@
*/
package org.openjdk.jmc.rjmx.internal;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.logging.Level;
+
+import javax.management.remote.JMXConnector;
import org.openjdk.jmc.common.io.IOToolkit;
import org.openjdk.jmc.rjmx.IServerHandle;
+import org.openjdk.jmc.rjmx.RJMXPlugin;
import org.openjdk.jmc.rjmx.common.ConnectionException;
import org.openjdk.jmc.rjmx.common.IConnectionDescriptor;
import org.openjdk.jmc.rjmx.common.IConnectionHandle;
@@ -118,6 +123,10 @@ private IConnectionHandle doConnect(String usage, IConnectionListener[] listener
if (isDisposed()) {
throw new ConnectionException("Server handle is disposed"); //$NON-NLS-1$
}
+ JMXConnector overriddenConnection = this.checkForProtocolSpecificConnectorExtension();
+ if (overriddenConnection != null) {
+ connection.specifyConnector(overriddenConnection);
+ }
performedConnect = connection.connect();
newConnectionHandle = new DefaultConnectionHandle(connection, usage, listeners,
ServiceFactoryInitializer.initializeFromExtensions());
@@ -129,6 +138,17 @@ private IConnectionHandle doConnect(String usage, IConnectionListener[] listener
return newConnectionHandle;
}
+ private JMXConnector checkForProtocolSpecificConnectorExtension() {
+ final IConnectionDescriptor descriptor = this.connection.getConnectionDescriptor();
+ try {
+ return new ProtocolInitializer().newJMXConnector(descriptor.createJMXServiceURL(),
+ descriptor.getEnvironment());
+ } catch (IOException e) {
+ RJMXPlugin.getDefault().getLogger().log(Level.INFO, "Error attempting JMX protocol extensions", e);
+ return null;
+ }
+ }
+
public void dispose(boolean gracefully) {
synchronized (this) {
if (!isDisposed()) {
diff --git a/application/pom.xml b/application/pom.xml
index c72fed7149..90dc2c96f2 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -111,6 +111,7 @@
org.openjdk.jmc.ui.celleditors
org.openjdk.jmc.updatesite.ide
org.openjdk.jmc.updatesite.rcp
+ org.openjdk.jmc.jolokia
l10n
tests
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/.classpath b/application/tests/org.openjdk.jmc.jolokia.test/.classpath
new file mode 100644
index 0000000000..4432907f44
--- /dev/null
+++ b/application/tests/org.openjdk.jmc.jolokia.test/.classpath
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 0000000000..b375b8037c
--- /dev/null
+++ b/application/tests/org.openjdk.jmc.jolokia.test/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Jolokia plugin test
+Bundle-SymbolicName: org.openjdk.jmc.jolokia.test;singleton:=true
+Bundle-Version: 9.1.0.qualifier
+Bundle-Vendor: Oracle Corporation
+Bundle-RequiredExecutionEnvironment: JavaSE-17
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.junit,
+ org.openjdk.jmc.jolokia,
+ org.eclipse.osgi,
+ org.eclipse.ui.workbench,
+ org.openjdk.jmc.rjmx,
+ org.eclipse.ui,
+ org.awaitility,
+ org.hamcrest
+Automatic-Module-Name: org.openjdk.jmc.jolokia.test
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/build.properties b/application/tests/org.openjdk.jmc.jolokia.test/build.properties
new file mode 100644
index 0000000000..b4608c8522
--- /dev/null
+++ b/application/tests/org.openjdk.jmc.jolokia.test/build.properties
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024, Kantega AS. 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 http://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.
+source.. = src/test/java/,\
+ src/test/resources/
+output.. = target/test-classes/
+bin.includes = META-INF/,.
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/pom.xml b/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
new file mode 100644
index 0000000000..e3a99bd6e1
--- /dev/null
+++ b/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
@@ -0,0 +1,83 @@
+
+
+
+ 4.0.0
+
+ org.openjdk.jmc
+ missioncontrol.application.tests
+ ${revision}${changelist}
+
+ org.openjdk.jmc.jolokia.test
+ eclipse-test-plugin
+
+
+ ${project.basedir}/../../../configuration
+ 1.7.2
+
+
+
+
+ org.awaitility
+ awaitility
+ 4.0.0
+
+
+ org.jolokia
+ jolokia-jvm
+ ${jolokia.agent.version}
+ test
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-surefire-plugin
+ ${tycho.version}
+
+ ${test.includes}
+
+
+
+ -javaagent:${settings.localRepository}/org/jolokia/jolokia-jvm/${jolokia.agent.version}/jolokia-jvm-${jolokia.agent.version}.jar=port=0,discover=true
+
+
+
+
+
+
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/src/test/java/org/openjdk/jmc/jolokia/JolokiaTest.java b/application/tests/org.openjdk.jmc.jolokia.test/src/test/java/org/openjdk/jmc/jolokia/JolokiaTest.java
new file mode 100644
index 0000000000..c99664e0f9
--- /dev/null
+++ b/application/tests/org.openjdk.jmc.jolokia.test/src/test/java/org/openjdk/jmc/jolokia/JolokiaTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Kantega AS. 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 http://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.jolokia;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.ReflectionException;
+import javax.management.MBeanServerFactory;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXServiceURL;
+
+import org.awaitility.Awaitility;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests that JMX connections done with JmcJolokiaJmxConnectionProvider are functional
+ */
+@SuppressWarnings("restriction")
+public class JolokiaTest {
+
+ static String jolokiaUrl;
+
+ private static Set unsafeAttributes = new HashSet<>(Arrays.asList("BootClassPath", "UsageThreshold",
+ "UsageThresholdExceeded", "UsageThresholdCount", "CollectionUsageThreshold",
+ "CollectionUsageThresholdExceeded", "CollectionUsageThresholdCount", "Config", "MBeanServerId"));
+
+ private static MBeanServerConnection jolokiaConnection, localConnection;
+
+ @BeforeClass
+ public static void startServer() throws Exception {
+ // wait for Jolokia to be ready before commencing tests
+ Awaitility.await().atMost(Duration.ofSeconds(15))//Note: hard code property to avoid module dependency on agent
+ .until(() -> (jolokiaUrl = System.getProperty("jolokia.agent")) != null);
+ jolokiaConnection = getJolokiaMBeanConnector();
+ localConnection = MBeanServerFactory.createMBeanServer();
+ }
+
+ @Test
+ public void testReadAttributesOverJolokia() throws MalformedURLException, IOException, OperationsException,
+ IntrospectionException, AttributeNotFoundException, ReflectionException, MBeanException {
+ int fetched = 0, compared = 0, unavailable = 0;
+ for (ObjectName objectName : jolokiaConnection.queryNames(null, null)) {
+ for (MBeanAttributeInfo attributeInfo : getJolokiaMBeanConnector().getMBeanInfo(objectName)
+ .getAttributes()) {
+ String attributeName = attributeInfo.getName();
+ if (!unsafeAttributes.contains(attributeName)) {
+ Object attribute = getJolokiaMBeanConnector().getAttribute(objectName, attributeName);
+ fetched++;
+ if (attribute instanceof String || attribute instanceof Boolean) { // Assume strings and booleans are safe to compare directly
+ try {
+ Object locallyRetrievedAttribute = localConnection.getAttribute(objectName, attributeName);
+ compared++;
+ Assert.assertEquals("Comparing returned value of " + objectName + "." + attributeName,
+ locallyRetrievedAttribute, attribute);
+ } catch (InstanceNotFoundException e) {
+ unavailable++;
+ }
+ }
+ }
+ }
+ }
+ System.out.println(" attribute test stats: fetched: " + fetched + ", compared: " + compared + ", unavailable: "
+ + unavailable);
+ }
+
+ @Test
+ public void testExecuteOperation() throws InstanceNotFoundException, MalformedObjectNameException, MBeanException,
+ ReflectionException, MalformedURLException, IOException {
+ jolokiaConnection.invoke(new ObjectName("java.lang:type=Memory"), "gc", new Object[0], new String[0]);
+ }
+
+ @Test
+ public void testWriteAttribute()
+ throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException,
+ MalformedObjectNameException, MBeanException, ReflectionException, MalformedURLException, IOException {
+ ObjectName objectName = new ObjectName("jolokia:type=Config");
+ String attribute = "Debug";
+ jolokiaConnection.setAttribute(objectName, new Attribute(attribute, true));
+ Assert.assertEquals(true, jolokiaConnection.getAttribute(objectName, attribute));
+ }
+
+ private static MBeanServerConnection getJolokiaMBeanConnector() throws IOException, MalformedURLException {
+ JMXConnector connector = new JmcJolokiaJmxConnectionProvider().newJMXConnector(
+ new JMXServiceURL(jolokiaUrl.replace("http", "service:jmx:jolokia")), Collections.emptyMap());
+ connector.connect();
+ MBeanServerConnection connection = connector.getMBeanServerConnection();
+ return connection;
+ }
+
+}
diff --git a/application/tests/pom.xml b/application/tests/pom.xml
index 910633a541..6140623a71 100644
--- a/application/tests/pom.xml
+++ b/application/tests/pom.xml
@@ -1,6 +1,6 @@