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 @@