diff --git a/agent/jmx/src/main/java/org/jolokia/jmx/JolokiaMBeanServer.java b/agent/jmx/src/main/java/org/jolokia/jmx/JolokiaMBeanServer.java index 6db8aed3a..9b403e674 100644 --- a/agent/jmx/src/main/java/org/jolokia/jmx/JolokiaMBeanServer.java +++ b/agent/jmx/src/main/java/org/jolokia/jmx/JolokiaMBeanServer.java @@ -108,6 +108,21 @@ private JsonMBean extractJsonMBeanAnnotation(Object object) { } } catch (IllegalAccessException e) { // Ignored silently, but we tried it at least + } catch (RuntimeException e) { + // See https://openjdk.java.net/jeps/403 + // On JDK9-JDK15 (with --illegal-access=deny) or on JDK-16+ (by default), + // java.lang.reflect.InaccessibleObjectException is thrown. + // --illegal-access=permit|warn|debug always ends with at least one WARNING message. The only + // way to handle the reflection gently is by using: + // --illegal-access=deny \ + // --add-opens java.management/javax.management.modelmbean=ALL-UNNAMED + // without deny, we can't detect up front (using JDK8 API) if we can safely call setAccessible()... + if (e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) { + // ignore + isAccessible = null; + } else { + throw e; + } } finally { if (isAccessible != null) { field.setAccessible(isAccessible); diff --git a/agent/jvm/pom.xml b/agent/jvm/pom.xml index e1a2ab4af..9e8701153 100644 --- a/agent/jvm/pom.xml +++ b/agent/jvm/pom.xml @@ -105,7 +105,6 @@ org.apache.maven.plugins maven-shade-plugin - 2.3 package @@ -153,7 +152,8 @@ org.apache.maven.plugins maven-surefire-plugin - always + 1 + false diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/AgentLauncher.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/AgentLauncher.java index a5960f208..e26c028c5 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/AgentLauncher.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/AgentLauncher.java @@ -50,7 +50,7 @@ public static void main(String... args) { OptionsAndArgs options; try { options = new OptionsAndArgs(CommandDispatcher.getAvailableCommands(),args); - VirtualMachineHandler vmHandler = new VirtualMachineHandler(options); + VirtualMachineHandlerOperations vmHandler = PlatformUtils.createVMAccess(options); CommandDispatcher dispatcher = new CommandDispatcher(options); // Attach a VirtualMachine to a given PID (if PID is given) diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/AbstractBaseCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/AbstractBaseCommand.java index 481c8a9c6..25661155f 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/AbstractBaseCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/AbstractBaseCommand.java @@ -17,12 +17,11 @@ */ import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Properties; import org.jolokia.jvmagent.JvmAgent; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Stateless Base command providing helper functions @@ -51,25 +50,24 @@ public abstract class AbstractBaseCommand { * @throws InvocationTargetException exception occured during startup of the agent. You probably need to examine * the stdout of the instrumented process as well for error messages. */ - abstract int execute(OptionsAndArgs pOpts, Object pVm,VirtualMachineHandler pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException; + abstract int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException; // ======================================================================================================= /** - * Execute {@link com.sun.tools.attach.VirtualMachine#loadAgent(String, String)} via reflection + * Execute {@code com.sun.tools.attach.VirtualMachine#loadAgent(String, String)} * * @param pVm the VirtualMachine object, typeless + * @param pHandler platform-specific way to invoke operations on VM * @param pOpts options from where to extract the agent path and options * @param pAdditionalOpts optional additional options to be appended to the agent options. Must be a CSV string. */ - protected void loadAgent(Object pVm, OptionsAndArgs pOpts,String ... pAdditionalOpts) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Class clazz = pVm.getClass(); - Method method = clazz.getMethod("loadAgent",String.class, String.class); + protected void loadAgent(Object pVm, VirtualMachineHandlerOperations pHandler, OptionsAndArgs pOpts, String ... pAdditionalOpts) { String args = pOpts.toAgentArg(); if (pAdditionalOpts.length > 0) { args = args.length() != 0 ? args + "," + pAdditionalOpts[0] : pAdditionalOpts[0]; } - method.invoke(pVm, pOpts.getJarFilePath(),args.length() > 0 ? args : null); + pHandler.loadAgent(pVm, pOpts.getJarFilePath(), args.length() > 0 ? args : null); } /** @@ -78,10 +76,11 @@ protected void loadAgent(Object pVm, OptionsAndArgs pOpts,String ... pAdditional * has been already attached and started. ("start" will set this property, "stop" will remove it). * * @param pVm the {@link com.sun.tools.attach.VirtualMachine}, but typeless + * @param pHandler platform-specific way to invoke operations on VM * @return the agent URL if it is was set by a previous 'start' command. */ - protected String checkAgentUrl(Object pVm) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - return checkAgentUrl(pVm, 0); + protected String checkAgentUrl(Object pVm, VirtualMachineHandlerOperations pHandler) { + return checkAgentUrl(pVm, pHandler, 0); } /** @@ -90,10 +89,11 @@ protected String checkAgentUrl(Object pVm) throws NoSuchMethodException, Invocat * has been already attached and started. ("start" will set this property, "stop" will remove it). * * @param pVm the {@link com.sun.tools.attach.VirtualMachine}, but typeless + * @param pHandler platform-specific way to invoke operations on VM * @param delayInMs wait that many ms before fetching the properties ** @return the agent URL if it is was set by a previous 'start' command. */ - protected String checkAgentUrl(Object pVm, int delayInMs) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + protected String checkAgentUrl(Object pVm, VirtualMachineHandlerOperations pHandler, int delayInMs) { if (delayInMs != 0) { try { Thread.sleep(delayInMs); @@ -101,47 +101,38 @@ protected String checkAgentUrl(Object pVm, int delayInMs) throws NoSuchMethodExc // just continue } } - Properties systemProperties = getAgentSystemProperties(pVm); + Properties systemProperties = getAgentSystemProperties(pVm, pHandler); return systemProperties.getProperty(JvmAgent.JOLOKIA_AGENT_URL); } /** * Execute {@link com.sun.tools.attach.VirtualMachine#getSystemProperties()} via reflection * @param pVm the VirtualMachine object, typeless + * @param pHandler platform-specific way to invoke operations on VM * @return the system properties */ - protected Properties getAgentSystemProperties(Object pVm) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Class clazz = pVm.getClass(); - Method method = clazz.getMethod("getSystemProperties"); - return (Properties) method.invoke(pVm); + protected Properties getAgentSystemProperties(Object pVm, VirtualMachineHandlerOperations pHandler) { + return pHandler.getSystemProperties(pVm); } /** * Get a description of the process attached, either the numeric id only or, if a pattern is given, * the pattern and the associated PID * - * @param pOpts options from where to take the PID or pattern * @param pHandler handler for looking up the process in case of a pattern lookup + * @param pOpts options from where to take the PID or pattern * @return a description of the process */ - protected String getProcessDescription(OptionsAndArgs pOpts, VirtualMachineHandler pHandler) { + protected String getProcessDescription(VirtualMachineHandlerOperations pHandler, OptionsAndArgs pOpts) { if (pOpts.getPid() != null) { return "PID " + pOpts.getPid(); } else if (pOpts.getProcessPattern() != null) { StringBuffer desc = new StringBuffer("process matching \"") .append(pOpts.getProcessPattern().pattern()) .append("\""); - try { - desc.append(" (PID: ") - .append(pHandler.findProcess(pOpts.getProcessPattern()).getId()) - .append(")"); - } catch (InvocationTargetException e) { - // ignored - } catch (NoSuchMethodException e) { - // ignored - } catch (IllegalAccessException e) { - // ignored - } + desc.append(" (PID: ") + .append(pHandler.findProcess(pOpts.getProcessPattern()).getId()) + .append(")"); return desc.toString(); } else { return "(null)"; diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/CommandDispatcher.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/CommandDispatcher.java index 4668d0578..d3c5d97c2 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/CommandDispatcher.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/CommandDispatcher.java @@ -20,7 +20,7 @@ import java.util.*; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Dispatch for various attach commands @@ -69,7 +69,7 @@ public CommandDispatcher(OptionsAndArgs pOptions) { * @param pHandler handler for listing processes * @return the return code (0 or 1) */ - public int dispatchCommand(Object pVm,VirtualMachineHandler pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + public int dispatchCommand(Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { String commandName = options.getCommand(); AbstractBaseCommand command = COMMANDS.get(commandName); if (command == null) { diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/EncryptCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/EncryptCommand.java index bd4a65802..5bc4de49d 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/EncryptCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/EncryptCommand.java @@ -1,7 +1,7 @@ package org.jolokia.jvmagent.client.command; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; import org.jolokia.util.*; import java.io.*; @@ -34,8 +34,8 @@ String getName() { } @Override - int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandler pHandler) - throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) + throws InvocationTargetException { try { List args = pOpts.getExtraArgs(); String password = args.size() == 0 ? diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java index 43701d3e5..818d08ab3 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java @@ -21,7 +21,7 @@ import org.jolokia.Version; import org.jolokia.config.ConfigKey; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Print out usage information @@ -40,7 +40,7 @@ String getName() { /** {@inheritDoc} */ @Override - int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandler pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { printUsage(); return 0; } diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ListCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ListCommand.java index f6765bb71..c9ae1d9bc 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ListCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ListCommand.java @@ -21,7 +21,6 @@ import java.util.List; import org.jolokia.jvmagent.client.util.*; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; /** * List all available Java processes @@ -40,7 +39,7 @@ String getName() { /** {@inheritDoc} */ @Override @SuppressWarnings("PMD.SystemPrintln") - int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandler pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { List vmDescriptors = pHandler.listProcesses(); for (ProcessDescription descriptor : vmDescriptors) { Formatter formatter = new Formatter().format("%7.7s %-100.100s", diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StartCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StartCommand.java index b95fab82e..825b665d6 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StartCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StartCommand.java @@ -16,10 +16,8 @@ * limitations under the License. */ -import java.lang.reflect.InvocationTargetException; - import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Load a Jolokia Agent and start it. Whether an agent is started is decided by the existence of the @@ -30,8 +28,8 @@ */ public class StartCommand extends AbstractBaseCommand { - @Override /** {@inheritDoc} */ + @Override String getName() { return "start"; } @@ -39,32 +37,31 @@ String getName() { /** {@inheritDoc} */ @Override @SuppressWarnings("PMD.SystemPrintln") - int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandler pHandler) - throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) { String agentUrl; - agentUrl = checkAgentUrl(pVm); + agentUrl = checkAgentUrl(pVm, pHandler); boolean quiet = pOpts.isQuiet(); if (agentUrl == null) { - loadAgent(pVm, pOpts); - agentUrl = checkAgentUrl(pVm); + loadAgent(pVm, pHandler, pOpts); + agentUrl = checkAgentUrl(pVm, pHandler); if (agentUrl == null) { // Wait a bit and try again - agentUrl = checkAgentUrl(pVm, 500); + agentUrl = checkAgentUrl(pVm, pHandler, 500); if (agentUrl == null) { - System.err.println("Couldn't start agent for " + getProcessDescription(pOpts, pHandler)); + System.err.println("Couldn't start agent for " + getProcessDescription(pHandler, pOpts)); System.err.println("Possible reason could be that port '" + pOpts.getPort() + "' is already occupied."); System.err.println("Please check the standard output of the target process for a detailed error message."); return 1; } } if (!quiet) { - System.out.println("Started Jolokia for " + getProcessDescription(pOpts,pHandler)); + System.out.println("Started Jolokia for " + getProcessDescription(pHandler, pOpts)); System.out.println(agentUrl); } return 0; } else { if (!quiet) { - System.out.println("Jolokia is already attached to " + getProcessDescription(pOpts,pHandler)); + System.out.println("Jolokia is already attached to " + getProcessDescription(pHandler, pOpts)); System.out.println(agentUrl); } return 1; diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StatusCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StatusCommand.java index 2ff0e54c8..947bb2d4a 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StatusCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StatusCommand.java @@ -19,7 +19,7 @@ import java.lang.reflect.InvocationTargetException; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Check the status of an agent on the target process. Prints out the information @@ -39,23 +39,24 @@ String getName() { /** * Checkt the status and print it out (except for --quiet * @param pVm the virtual machine + * @param pHandler platform-specific way to invoke operations on VM * @return the exit code (0: agent is attached, 1: agent is not attached.) */ @Override @SuppressWarnings("PMD.SystemPrintln") - int execute(OptionsAndArgs pOptions, Object pVm, VirtualMachineHandler pHandler) + int execute(OptionsAndArgs pOptions, Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { - String agentUrl = checkAgentUrl(pVm); + String agentUrl = checkAgentUrl(pVm, pHandler); boolean quiet = pOptions.isQuiet(); if (agentUrl != null) { if (!quiet) { - System.out.println("Jolokia started for " + getProcessDescription(pOptions,pHandler)); + System.out.println("Jolokia started for " + getProcessDescription(pHandler, pOptions)); System.out.println(agentUrl); } return 0; } else { if (!quiet) { - System.out.println("No Jolokia agent attached to " + getProcessDescription(pOptions,pHandler)); + System.out.println("No Jolokia agent attached to " + getProcessDescription(pHandler, pOptions)); } return 1; } diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StopCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StopCommand.java index 7c464f14e..aa2b5452b 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StopCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/StopCommand.java @@ -19,7 +19,7 @@ import java.lang.reflect.InvocationTargetException; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Stop a Jolokia Agent, but only if it is already running (started with 'start'). @@ -40,18 +40,18 @@ String getName() { /** {@inheritDoc} */ @Override @SuppressWarnings("PMD.SystemPrintln") - int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandler pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { - String agentUrl = checkAgentUrl(pVm); + int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + String agentUrl = checkAgentUrl(pVm, pHandler); boolean quiet = pOpts.isQuiet(); if (agentUrl != null) { - loadAgent(pVm,pOpts,"mode=stop"); + loadAgent(pVm, pHandler, pOpts, "mode=stop"); if (!quiet) { - System.out.println("Stopped Jolokia for " + getProcessDescription(pOpts,pHandler)); + System.out.println("Stopped Jolokia for " + getProcessDescription(pHandler, pOpts)); } return 0; } else { if (!quiet) { - System.out.println("Jolokia is not attached to " + getProcessDescription(pOpts,pHandler)); + System.out.println("Jolokia is not attached to " + getProcessDescription(pHandler, pOpts)); } return 1; } diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ToggleCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ToggleCommand.java index ddade0817..422628771 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ToggleCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/ToggleCommand.java @@ -19,7 +19,7 @@ import java.lang.reflect.InvocationTargetException; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Toggle between "start" and "stop" depending on the existance of the system @@ -42,8 +42,8 @@ String getName() { /** {@inheritDoc} */ @Override - int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandler pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { - return checkAgentUrl(pVm) == null ? + int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + return checkAgentUrl(pVm, pHandler) == null ? startCommand.execute(pOpts, pVm, pHandler) : stopCommand.execute(pOpts,pVm,pHandler); } diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/VersionCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/VersionCommand.java index 768b43591..7183418b4 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/VersionCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/VersionCommand.java @@ -20,7 +20,7 @@ import org.jolokia.Version; import org.jolokia.jvmagent.client.util.OptionsAndArgs; -import org.jolokia.jvmagent.client.util.VirtualMachineHandler; +import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations; /** * Print out the version of the agent @@ -36,7 +36,7 @@ String getName() { @Override @SuppressWarnings({"PMD.SystemPrintln"}) - int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandler pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + int execute(OptionsAndArgs pOpts, Object pVm, VirtualMachineHandlerOperations pHandler) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { StringBuilder version = new StringBuilder("Jolokia JVM Agent ").append(Version.getAgentVersion()); if (pOpts.isVerbose()) { version.append(" (Protocol: ").append(Version.getProtocolVersion()).append(")"); diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/DirectVirtualMachineHandler.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/DirectVirtualMachineHandler.java new file mode 100644 index 000000000..db4e4e64d --- /dev/null +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/DirectVirtualMachineHandler.java @@ -0,0 +1,115 @@ +package org.jolokia.jvmagent.client.util; + +/* + * Copyright 2009-2021 Roland Huss + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.sun.tools.attach.AgentInitializationException; +import com.sun.tools.attach.AgentLoadException; +import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.regex.Pattern; + +/** + * A handler for dealing with VirtualMachine directly accessing {@link com.sun.tools.attach.VirtualMachine} + * class available in {@code jdk.attach} module. + * + * @author ggrzybek + * @since 12.08.11 + */ +class DirectVirtualMachineHandler implements VirtualMachineHandlerOperations { + + private final OptionsAndArgs options; + + DirectVirtualMachineHandler(OptionsAndArgs options) { + this.options = options; + } + + @Override + public Object attachVirtualMachine() throws ProcessingException { + if (options.getPid() == null && options.getProcessPattern() == null) { + return null; + } + String pid = PlatformUtils.getProcessId(this, options); + try { + return VirtualMachine.attach(pid); + } catch (AttachNotSupportedException e) { + throw new ProcessingException(getPidErrorMesssage(pid, "AttachNotSupportedException"), e, options); + } catch (IOException e) { + throw new ProcessingException(getPidErrorMesssage(pid, "InvocationTarget"), e, options); + } catch (IllegalArgumentException e) { + throw new ProcessingException("Illegal Argument", e, options); + } + } + + private String getPidErrorMesssage(String pid, String label) { + return pid != null ? + String.format("Cannot attach to process-ID %s (%s %s).\nSee --help for possible reasons.", + pid, label, VirtualMachine.class.getName()) : + String.format("%s %s",label, VirtualMachine.class.getName()); + } + + @Override + public void detachAgent(Object pVm) throws ProcessingException { + try { + ((VirtualMachine) pVm).detach(); + } catch (IOException e) { + throw new ProcessingException("Error while detaching", e, options); + } + } + + @Override + public List listProcesses() { + List ret = new ArrayList(); + for (VirtualMachineDescriptor descriptor : VirtualMachine.list()) { + ret.add(new ProcessDescription(descriptor.id(), descriptor.displayName())); + } + return ret; + } + + @Override + public ProcessDescription findProcess(Pattern pPattern) { + return PlatformUtils.findProcess(pPattern, listProcesses()); + } + + @Override + public void loadAgent(Object pVm, String jarFilePath, String args) { + try { + ((VirtualMachine) pVm).loadAgent(jarFilePath, args); + } catch (AgentLoadException e) { + throw new ProcessingException("Error while loading Jolokia agent to a JVM process", e, options); + } catch (AgentInitializationException e) { + throw new ProcessingException("Error while loading Jolokia agent to a JVM process", e, options); + } catch (IOException e) { + throw new ProcessingException("Error while loading Jolokia agent to a JVM process", e, options); + } + } + + @Override + public Properties getSystemProperties(Object pVm) { + try { + return ((VirtualMachine) pVm).getSystemProperties(); + } catch (IOException e) { + throw new ProcessingException("Error while getting system properties from a JVM process", e, options); + } + } + +} diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/PlatformUtils.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/PlatformUtils.java new file mode 100644 index 000000000..2a19e1e2f --- /dev/null +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/PlatformUtils.java @@ -0,0 +1,116 @@ +package org.jolokia.jvmagent.client.util; + +/* + * Copyright 2009-2021 Roland Huss + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PlatformUtils { + + private PlatformUtils() {} + + public static VirtualMachineHandlerOperations createVMAccess(OptionsAndArgs options) { + String version = System.getProperty("java.specification.version"); + if (version == null || "".equals(version.trim())) { + // fallback to reflection based access + return new VirtualMachineHandler(options); + } + if (version.contains(".")) { + version = version.substring(version.lastIndexOf('.') + 1); + } + try { + int v = Integer.parseInt(version); + if (v <= 8) { + // Java 8 or earlier, where Attach API classes are located in tools.jar, which has to be on classpath + // or can be detected by Jolokia relatively to ${java.home} + return new VirtualMachineHandler(options); + } else { + // we can create a small JDK image using: + // jlink --add-modules=java.se --output /tmp/small-jdk + // and run the agent using: + // /tmp/small-jdk/bin/java -cp jolokia-jvm.jar org.jolokia.jvmagent.client.AgentLauncher list + // but such image won't contain jdk.attach Java module. So we have to detect its existence + try { + return new DirectVirtualMachineHandler(options); + } catch (NoClassDefFoundError e) { + throw new ProcessingException("Can't load com.sun.tools.attach.VirtualMachine class." + + " Is \"jdk.attach\" standard module available?", e, options); + } + } + } catch (NumberFormatException e) { + // again, fallback silently + return new VirtualMachineHandler(options); + } + } + + // Try to find out own process id. This is platform dependent and works on Sun/Oracl/OpeneJDKs like the + // whole agent, so it should be safe + static String getOwnProcessId() { + // Format of name is : @ + String name = ManagementFactory.getRuntimeMXBean().getName(); + int endIdx = name.indexOf('@'); + return endIdx != -1 ? name.substring(0,endIdx) : name; + } + + public static ProcessDescription findProcess(Pattern pPattern, List processes) { + List ret = new ArrayList(); + String ownId = PlatformUtils.getOwnProcessId(); + + for (ProcessDescription desc : processes) { + Matcher matcher = pPattern.matcher(desc.getDisplay()); + if (!desc.getId().equals(ownId) && matcher.find()) { + ret.add(desc); + } + } + if (ret.size() == 1) { + return ret.get(0); + } else if (ret.size() == 0) { + throw new IllegalArgumentException("No attachable process found matching \"" + pPattern.pattern() + "\""); + } else { + StringBuilder buf = new StringBuilder(); + for (ProcessDescription desc : ret) { + buf.append(desc.getId()).append(" (").append(desc.getDisplay()).append("),"); + } + throw new IllegalArgumentException("More than one attachable process found matching \"" + + pPattern.pattern() + "\": " + buf.substring(0,buf.length()-1)); + } + } + + /** + * Get the process id, either directly from option's ID or by looking up a regular expression for java process name + * (but not this java process) + * + * @param pHandler platform-specific way to invoke operations on VM + * @param pOpts used to get eithe the process Id ({@link OptionsAndArgs#getPid()} or the pattern for matching a + * process name ({@link OptionsAndArgs#getProcessPattern()}) + * @return the numeric id as string + * @throws IllegalArgumentException if a pattern is used and no or more than one process name matches. + */ + public static String getProcessId(VirtualMachineHandlerOperations pHandler, OptionsAndArgs pOpts) { + if (pOpts.getPid() != null) { + return pOpts.getPid(); + } else if (pOpts.getProcessPattern() != null) { + return pHandler.findProcess(pOpts.getProcessPattern()).getId(); + } else { + throw new IllegalArgumentException("No process ID and no process name pattern given"); + } + } + +} diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/ProcessingException.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/ProcessingException.java index 5ef6ec46a..940ad7956 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/ProcessingException.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/ProcessingException.java @@ -34,7 +34,7 @@ public class ProcessingException extends RuntimeException { * @param pStoredExp the original exception * @param pOptions options from where to take the information how the error should be logged */ - public ProcessingException(String pErrMsg, Exception pStoredExp, OptionsAndArgs pOptions) { + public ProcessingException(String pErrMsg, Throwable pStoredExp, OptionsAndArgs pOptions) { super(pErrMsg,pStoredExp); quiet = pOptions.isQuiet(); verbose = pOptions.isVerbose(); diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/VirtualMachineHandler.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/VirtualMachineHandler.java index 7d661a93f..3d0e0c751 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/VirtualMachineHandler.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/VirtualMachineHandler.java @@ -16,25 +16,23 @@ * limitations under the License. */ -import java.lang.management.ManagementFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; +import java.util.Properties; import java.util.regex.Pattern; - /** * A handler for dealing with VirtualMachine without directly referencing internally - * the class type. All lookup is done via reflection. + * the class type. All lookup is done via reflection. (Name not changed for compatibility reasons). * * @author roland * @since 12.08.11 */ -public class VirtualMachineHandler { +class VirtualMachineHandler implements VirtualMachineHandlerOperations { - private OptionsAndArgs options; + private final OptionsAndArgs options; /** * Constructor with options @@ -42,7 +40,7 @@ public class VirtualMachineHandler { * @param pOptions options for getting e.g. the process id to attach to * */ - public VirtualMachineHandler(OptionsAndArgs pOptions) { + VirtualMachineHandler(OptionsAndArgs pOptions) { options = pOptions; } @@ -56,15 +54,16 @@ public VirtualMachineHandler(OptionsAndArgs pOptions) { * * @return the create virtual machine of null if none could be created */ - public Object attachVirtualMachine() { + @Override + public Object attachVirtualMachine() throws ProcessingException { if (options.getPid() == null && options.getProcessPattern() == null) { return null; } - Class vmClass = lookupVirtualMachineClass(); + Class vmClass = lookupVirtualMachineClass(); String pid = null; try { Method method = vmClass.getMethod("attach",String.class); - pid = getProcessId(options); + pid = PlatformUtils.getProcessId(this, options); return method.invoke(null, pid); } catch (NoSuchMethodException e) { throw new ProcessingException("Internal: No method 'attach' found on " + vmClass,e,options); @@ -77,7 +76,7 @@ public Object attachVirtualMachine() { } } - private String getPidErrorMesssage(String pid, String label, Class vmClass) { + private String getPidErrorMesssage(String pid, String label, Class vmClass) { return pid != null ? String.format("Cannot attach to process-ID %s (%s %s).\nSee --help for possible reasons.", pid, label, vmClass.getName()) : @@ -89,10 +88,11 @@ private String getPidErrorMesssage(String pid, String label, Class vmClass) { * * @param pVm the virtual machine to detach from */ + @Override public void detachAgent(Object pVm) { try { if (pVm != null) { - Class clazz = pVm.getClass(); + Class clazz = pVm.getClass(); Method method = clazz.getMethod("detach"); method.setAccessible(true); // on J9 you get IllegalAccessException otherwise. method.invoke(pVm); @@ -109,23 +109,30 @@ public void detachAgent(Object pVm) { /** * Return a list of all Java processes * @return list of java processes - * @throws NoSuchMethodException reflection error - * @throws InvocationTargetException reflection error - * @throws IllegalAccessException reflection error + * @throws ProcessingException reflection error */ - public List listProcesses() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + @Override + public List listProcesses() { List ret = new ArrayList(); - Class vmClass = lookupVirtualMachineClass(); - Method method = vmClass.getMethod("list"); - List vmDescriptors = (List) method.invoke(null); - for (Object descriptor : vmDescriptors) { - Method idMethod = descriptor.getClass().getMethod("id"); - String id = (String) idMethod.invoke(descriptor); - Method displayMethod = descriptor.getClass().getMethod("displayName"); - String display = (String) displayMethod.invoke(descriptor); - ret.add(new ProcessDescription(id, display)); + Class vmClass = lookupVirtualMachineClass(); + try { + Method method = vmClass.getMethod("list"); + List vmDescriptors = (List) method.invoke(null); + for (Object descriptor : vmDescriptors) { + Method idMethod = descriptor.getClass().getMethod("id"); + String id = (String) idMethod.invoke(descriptor); + Method displayMethod = descriptor.getClass().getMethod("displayName"); + String display = (String) displayMethod.invoke(descriptor); + ret.add(new ProcessDescription(id, display)); + } + return ret; + } catch (NoSuchMethodException e) { + throw new ProcessingException("Error while listing JVM processes", e, options); + } catch (InvocationTargetException e) { + throw new ProcessingException("Error while listing JVM processes", e, options); + } catch (IllegalAccessException e) { + throw new ProcessingException("Error while listing JVM processes", e, options); } - return ret; } /** @@ -137,63 +144,45 @@ public List listProcesses() throws NoSuchMethodException, In * @return a process description of the one process found but never null * @throws IllegalArgumentException if more than one or no process has been found. */ - public ProcessDescription findProcess(Pattern pPattern) - throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { - List ret = new ArrayList(); - String ownId = getOwnProcessId(); + @Override + public ProcessDescription findProcess(Pattern pPattern) { + return PlatformUtils.findProcess(pPattern, listProcesses()); + } - for (ProcessDescription desc : listProcesses()) { - Matcher matcher = pPattern.matcher(desc.getDisplay()); - if (!desc.getId().equals(ownId) && matcher.find()) { - ret.add(desc); - } - } - if (ret.size() == 1) { - return ret.get(0); - } else if (ret.size() == 0) { - throw new IllegalArgumentException("No attachable process found matching \"" + pPattern.pattern() + "\""); - } else { - StringBuilder buf = new StringBuilder(); - for (ProcessDescription desc : ret) { - buf.append(desc.getId()).append(" (").append(desc.getDisplay()).append("),"); - } - throw new IllegalArgumentException("More than one attachable process found matching \"" + - pPattern.pattern() + "\": " + buf.substring(0,buf.length()-1)); + @Override + public void loadAgent(Object pVm, String jarFilePath, String args) throws ProcessingException { + Class clazz = pVm.getClass(); + try { + Method method = clazz.getMethod("loadAgent",String.class, String.class); + method.invoke(pVm, jarFilePath, args); + } catch (NoSuchMethodException e) { + throw new ProcessingException("Error while loading Jolokia agent to a JVM process", e, options); + } catch (InvocationTargetException e) { + throw new ProcessingException("Error while loading Jolokia agent to a JVM process", e, options); + } catch (IllegalAccessException e) { + throw new ProcessingException("Error while loading Jolokia agent to a JVM process", e, options); } } - // ======================================================================================================== - - /** - * Get the process id, either directly from option's ID or by looking up a regular expression for java process name - * (but not this java process) - * - * @param pOpts used to get eithe the process Id ({@link OptionsAndArgs#getPid()} or the pattern for matching a - * process name ({@link OptionsAndArgs#getProcessPattern()}) - * @return the numeric id as string - * @throws IllegalArgumentException if a pattern is used and no or more than one process name matches. - */ - private String getProcessId(OptionsAndArgs pOpts) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { - if (pOpts.getPid() != null) { - return pOpts.getPid(); - } else if (pOpts.getProcessPattern() != null) { - return findProcess(pOpts.getProcessPattern()).getId(); - } else { - throw new IllegalArgumentException("No process ID and no process name pattern given"); + @Override + public Properties getSystemProperties(Object pVm) { + Class clazz = pVm.getClass(); + try { + Method method = clazz.getMethod("getSystemProperties"); + return (Properties) method.invoke(pVm); + } catch (NoSuchMethodException e) { + throw new ProcessingException("Error while getting system properties from a JVM process", e, options); + } catch (InvocationTargetException e) { + throw new ProcessingException("Error while getting system properties from a JVM process", e, options); + } catch (IllegalAccessException e) { + throw new ProcessingException("Error while getting system properties from a JVM process", e, options); } } - // Try to find out own process id. This is platform dependent and works on Sun/Oracl/OpeneJDKs like the - // whole agent, so it should be safe - private String getOwnProcessId() { - // Format of name is : @ - String name = ManagementFactory.getRuntimeMXBean().getName(); - int endIdx = name.indexOf('@'); - return endIdx != -1 ? name.substring(0,endIdx) : name; - } + // ======================================================================================================== // lookup virtual machine class - private Class lookupVirtualMachineClass() { + private Class lookupVirtualMachineClass() { try { return ToolsClassFinder.lookupClass("com.sun.tools.attach.VirtualMachine"); } catch (ClassNotFoundException exp) { diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/VirtualMachineHandlerOperations.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/VirtualMachineHandlerOperations.java new file mode 100644 index 000000000..c4265950d --- /dev/null +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/VirtualMachineHandlerOperations.java @@ -0,0 +1,85 @@ +package org.jolokia.jvmagent.client.util; + +/* + * Copyright 2009-2021 Roland Huss + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; +import java.util.Properties; +import java.util.regex.Pattern; + +/** + *

A contract for dealing with VirtualMachine on any JDK where + * Attach API is supported.

+ * + *

The virtual machine is passed as {@link Object} and dealt with differently in chosen implementation of the + * contract.

+ * + * @author ggrzybek + * @since 24.06.2021 + */ +public interface VirtualMachineHandlerOperations { + + /** + * Lookup and create a {@code com.sun.tools.attach.VirtualMachine} + * + * @return the create virtual machine of null if none could be created + * @throws ProcessingException for any problem related to VM attaching. Specific to particular implementation. + */ + Object attachVirtualMachine() throws ProcessingException; + + /** + * Detach from the virtual machine + * + * @param pVm the virtual machine to detach from + * @throws ProcessingException for any problem related to VM detaching. Specific to particular implementation. + */ + void detachAgent(Object pVm) throws ProcessingException; + + /** + * Return a list of all Java processes + * @return list of java processes + */ + List listProcesses(); + + /** + * Filter the process list for a regular expression and returns the description. The process this + * JVM is running in is ignored. If more than one process or no process is found, an exception + * is raised. + * + * @param pPattern regular expression to match + * @return a process description of the one process found but never null + * @throws IllegalArgumentException if more than one or no process has been found. + */ + ProcessDescription findProcess(Pattern pPattern); + + /** + * Loads Jolokia agent into the attached VM. + * + * @param pVm {@link com.sun.tools.attach.VirtualMachine} access object + * @param jarFilePath path to Java agent JAR file + * @param args arguments to {@link com.sun.tools.attach.VirtualMachine#loadAgent(String, String)} method + */ + void loadAgent(Object pVm, String jarFilePath, String args); + + /** + * Returns system properties from attached VM. + * + * @param pVm {@link com.sun.tools.attach.VirtualMachine} access object + * @return system properties of the remote VM + */ + Properties getSystemProperties(Object pVm); + +} diff --git a/agent/jvm/src/test/java/org/jolokia/jvmagent/client/command/CommandDispatcherTest.java b/agent/jvm/src/test/java/org/jolokia/jvmagent/client/command/CommandDispatcherTest.java index 25140ea98..5b9255a5c 100644 --- a/agent/jvm/src/test/java/org/jolokia/jvmagent/client/command/CommandDispatcherTest.java +++ b/agent/jvm/src/test/java/org/jolokia/jvmagent/client/command/CommandDispatcherTest.java @@ -88,7 +88,7 @@ public void versionVerbose() throws InvocationTargetException, NoSuchMethodExcep public void list() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { CommandDispatcher d = new CommandDispatcher(opts("list")); - VirtualMachineHandler vmh = createMock(VirtualMachineHandler.class); + VirtualMachineHandlerOperations vmh = createMock(VirtualMachineHandlerOperations.class); List ret = new ArrayList(); ret.add(new ProcessDescription("12","TestProcess")); expect(vmh.listProcesses()).andReturn(ret); @@ -103,12 +103,12 @@ public void list() throws InvocationTargetException, NoSuchMethodException, Ille public void descriptionWithPattern() throws AgentInitializationException, InvocationTargetException, IOException, NoSuchMethodException, AgentLoadException, IllegalAccessException { CommandDispatcher d = new CommandDispatcher(opts("start","blub")); - VirtualMachineHandler vmh = createMock(VirtualMachineHandler.class); + VirtualMachineHandlerOperations vmh = createMock(VirtualMachineHandlerOperations.class); VirtualMachine vm = createMock(VirtualMachine.class); - expect(vm.getSystemProperties()).andReturn(getProperties(false)); - expect(vm.getSystemProperties()).andReturn(getProperties(true)); + expect(vmh.getSystemProperties(EasyMock.eq(vm))).andReturn(getProperties(false)); + expect(vmh.getSystemProperties(EasyMock.eq(vm))).andReturn(getProperties(true)); // Agent should be loaded for successful switch - vm.loadAgent(EasyMock.anyObject(), EasyMock.anyObject()); + vmh.loadAgent(EasyMock.eq(vm), EasyMock.anyObject(), EasyMock.anyObject()); expect(vmh.findProcess(patternMatcher("blub"))).andReturn(new ProcessDescription("18", "bla blub blie")); replay(vm, vmh); @@ -138,15 +138,18 @@ public void status() throws IOException, InvocationTargetException, NoSuchMethod testStatus(false,1); } - @Test(expectedExceptions = InvocationTargetException.class) + @Test(expectedExceptions = ProcessingException.class) public void throwException() throws IOException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { CommandDispatcher d = new CommandDispatcher(opts("start", "42")); - VirtualMachine vm = createMock(VirtualMachine.class); + VirtualMachineHandlerOperations vmh = createMock(VirtualMachineHandlerOperations.class); + final VirtualMachine vm = createMock(VirtualMachine.class); expect(vm.getSystemProperties()).andThrow(new IOException()); - replay(vm); + expect(vmh.getSystemProperties(EasyMock.eq(vm))).andThrow(new ProcessingException("", new IOException(), + new OptionsAndArgs(CommandDispatcher.getAvailableCommands()))); + replay(vm, vmh); - d.dispatchCommand(vm,null); + d.dispatchCommand(vm,vmh); } @Test(expectedExceptions = IllegalArgumentException.class,expectedExceptionsMessageRegExp = ".*Unknown.*") @@ -162,15 +165,15 @@ private void testCommand(String pCommand, boolean pActive, int pRc, String... pP String p = pProcess.length > 0 ? pProcess[0] : "42"; CommandDispatcher d = new CommandDispatcher(opts(pCommand,p)); - VirtualMachineHandler vmh = createMock(VirtualMachineHandler.class); + VirtualMachineHandlerOperations vmh = createMock(VirtualMachineHandlerOperations.class); VirtualMachine vm = createMock(VirtualMachine.class); - expect(vm.getSystemProperties()).andReturn(getProperties(pActive)).times(pCommand.equals("toggle") ? 2 : 1); + expect(vmh.getSystemProperties(EasyMock.eq(vm))).andReturn(getProperties(pActive)).times(pCommand.equals("toggle") ? 2 : 1); if (!pActive && !pCommand.equals("stop")) { - expect(vm.getSystemProperties()).andReturn(getProperties(true)); + expect(vmh.getSystemProperties(EasyMock.eq(vm))).andReturn(getProperties(true)); } if (pRc == 0) { // Agent should be loaded for successful switch - vm.loadAgent(EasyMock.anyObject(), EasyMock.anyObject()); + vmh.loadAgent(EasyMock.eq(vm), EasyMock.anyObject(), EasyMock.anyObject()); } replay(vm,vmh); @@ -184,10 +187,11 @@ private void testStatus(boolean pActive,int pRc) throws IOException, InvocationT CommandDispatcher d = new CommandDispatcher(opts("status", "18")); VirtualMachine vm = createMock(VirtualMachine.class); - expect(vm.getSystemProperties()).andReturn(getProperties(pActive)).anyTimes(); - replay(vm); + VirtualMachineHandlerOperations vmh = createMock(VirtualMachineHandlerOperations.class); + expect(vmh.getSystemProperties(EasyMock.eq(vm))).andReturn(getProperties(pActive)).anyTimes(); + replay(vm, vmh); - assertEquals(d.dispatchCommand(vm,null), pRc); + assertEquals(d.dispatchCommand(vm,vmh), pRc); verify(vm); } diff --git a/agent/jvm/src/test/java/org/jolokia/jvmagent/client/util/VirtualMachineHandlerTest.java b/agent/jvm/src/test/java/org/jolokia/jvmagent/client/util/VirtualMachineHandlerTest.java index 46d33effa..37c4de5c3 100644 --- a/agent/jvm/src/test/java/org/jolokia/jvmagent/client/util/VirtualMachineHandlerTest.java +++ b/agent/jvm/src/test/java/org/jolokia/jvmagent/client/util/VirtualMachineHandlerTest.java @@ -34,12 +34,12 @@ @Test(groups = "java6") public class VirtualMachineHandlerTest { - VirtualMachineHandler vmHandler; + VirtualMachineHandlerOperations vmHandler; @BeforeTest public void setup() { - OptionsAndArgs o = new OptionsAndArgs(CommandDispatcher.getAvailableCommands(),new String[0]); - vmHandler = new VirtualMachineHandler(o); + OptionsAndArgs o = new OptionsAndArgs(CommandDispatcher.getAvailableCommands()); + vmHandler = PlatformUtils.createVMAccess(o); } @@ -112,7 +112,7 @@ private String getOwnProcessId() { private boolean tryAttach(String pId,String ... expMsg) throws Exception { OptionsAndArgs o = new OptionsAndArgs(CommandDispatcher.getAvailableCommands(),"start", pId); - VirtualMachineHandler h = new VirtualMachineHandler(o); + VirtualMachineHandlerOperations h = PlatformUtils.createVMAccess(o); Object vm = null; try { vm = h.attachVirtualMachine(); diff --git a/pom.xml b/pom.xml index 254107360..db2a349f9 100644 --- a/pom.xml +++ b/pom.xml @@ -165,12 +165,12 @@ maven-compiler-plugin - 3.2 + 3.8.1 maven-assembly-plugin - 2.5.1 + 3.3.0 @@ -215,13 +215,13 @@ maven-war-plugin - 2.5 + 3.3.1 org.apache.maven.plugins maven-shade-plugin - 2.3 + 3.2.4 @@ -231,7 +231,12 @@ maven-surefire-plugin - 2.18.1 + 2.22.2 + + + + maven-failsafe-plugin + 2.22.2 @@ -580,7 +585,7 @@ org.easymock easymock - 4.2 + 4.3 test @@ -751,6 +756,34 @@ + + java9+ + + [9,) + + + + + + maven-surefire-plugin + + + + --illegal-access=deny + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.management/javax.management.modelmbean=ALL-UNNAMED + + + + + + + + disable-javadoc-lint