# HG changeset patch # User Mario Torre # Date 1507557370 -7200 # Node ID 1a0d260468d1b93f047e5a94f7984476a9fcfd90 # Parent bde0a709ca3039a7bc0c5c800d72f150a90b02be Initial JCMD Plugin review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/025195.html reviewed-by: stooke diff -r bde0a709ca30 -r 1a0d260468d1 distribution/assembly/plugin-assembly.xml --- a/distribution/assembly/plugin-assembly.xml Fri Oct 06 14:14:13 2017 -0400 +++ b/distribution/assembly/plugin-assembly.xml Mon Oct 09 15:56:10 2017 +0200 @@ -61,6 +61,7 @@ com.redhat.thermostat.agent:thermostat-commands-distribution com.redhat.thermostat.agent:thermostat-killvm-distribution com.redhat.thermostat.agent:thermostat-vm-compiler-distribution + com.redhat.thermostat.agent:thermostat-jcmd-stats-collector-distribution diff -r bde0a709ca30 -r 1a0d260468d1 distribution/pom.xml --- a/distribution/pom.xml Fri Oct 06 14:14:13 2017 -0400 +++ b/distribution/pom.xml Mon Oct 09 15:56:10 2017 +0200 @@ -466,6 +466,12 @@ com.redhat.thermostat.agent + thermostat-jcmd-stats-collector-distribution + ${project.version} + zip + + + com.redhat.thermostat.agent thermostat-host-cpu-distribution ${project.version} zip diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/pom.xml Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,156 @@ + + + + 4.0.0 + + + thermostat-jcmd-stats-collector + com.redhat.thermostat.agent + 2.99.0-SNAPSHOT + + + thermostat-jcmd-stats-collector-agent + bundle + Thermostat JCMD Stats Collector Agent plugin + + + + + org.apache.felix + maven-bundle-plugin + true + + + Red Hat, Inc. + com.redhat.thermostat.agent.jcmd + + com.redhat.thermostat.agent.jcmd.backend.internal, + com.redhat.thermostat.agent.jcmd.backend.internal.model, + + + <_nouses>true + + + + + org.apache.felix + maven-scr-plugin + + + generate-scr-scrdescriptor + + scr + + + + + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + com.redhat.thermostat.agent + thermostat-common-core + ${project.version} + + + com.redhat.thermostat.agent + thermostat-common-plugin + ${project.version} + + + com.redhat.thermostat.agent + thermostat-common-portability + ${project.version} + + + com.redhat.thermostat.agent + thermostat-agent-core + ${project.version} + + + com.redhat.thermostat.agent + thermostat-storage-core + ${project.version} + + + com.redhat.thermostat.agent + thermostat-jvm-overview-agent + ${project.version} + + + com.redhat.thermostat.agent + thermostat-commands-agent + ${project.version} + + + com.redhat.thermostat.agent + thermostat-common-test + ${project.version} + test + + + + org.apache.felix + org.apache.felix.scr.annotations + + + diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/JCMDBackend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/JCMDBackend.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,135 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal; + +import com.redhat.thermostat.agent.http.HttpRequestService; +import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BaseBackend; +import com.redhat.thermostat.commands.agent.receiver.RequestReceiver; + +import com.redhat.thermostat.common.config.experimental.ConfigurationInfoSource; +import com.redhat.thermostat.jvm.overview.agent.model.VmMapperService; +import com.redhat.thermostat.lang.schema.JSONService; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.Service; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +import java.util.Dictionary; +import java.util.Hashtable; + +@Component +@Service(value = Backend.class) +public class JCMDBackend extends BaseBackend { + + private boolean enabled = false; + + private ServiceRegistration reg; + private JMXReceiver receiver; + private JMXConnectionManager connectionManager; + + private BundleContext context; + + @Reference + private MXBeanConnectionPool mxBeanPool; + + @Reference + private JSONService json; + + @Reference + private HttpRequestService httpRequestService; + + @Reference + private ConfigurationInfoSource configInfoSource; + + @Reference + private VmMapperService mapperService; + + public JCMDBackend() { + super("JCMD Stats Collector Backend", + "Gathers stats from JVM with diagnostic options enabled", + "Red Hat, Inc."); + } + + @Activate + void _activate_(BundleContext context) { + this.context = context; + if (connectionManager == null) { + connectionManager = new JMXConnectionManager(mxBeanPool); + NetworkHandler networkHandler = new NetworkHandler(httpRequestService, configInfoSource); + receiver = new JMXReceiver(connectionManager, json, mapperService, networkHandler); + } + } + + @Deactivate + private void _deactivate_(BundleContext context) { + if (reg != null) { + reg.unregister(); + reg = null; + } + } + + @Override + public boolean activate() { + enabled = true; + + if (reg == null) { + Dictionary serviceProperties = new Hashtable<>(); + serviceProperties.put("servicename", "jcmd"); + reg = context.registerService(RequestReceiver.class, receiver, serviceProperties); + } + + return true; + } + + @Override + public boolean deactivate() { + enabled = false; + _deactivate_(this.context); + return true; + } + + @Override + public boolean isActive() { + return enabled; + } + +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/JMXConnectionManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/JMXConnectionManager.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal; + +import com.redhat.thermostat.agent.utils.management.MXBeanConnection; +import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.agent.jcmd.backend.internal.model.JCMDBinding; +import com.redhat.thermostat.lang.schema.models.Pid; + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +public class JMXConnectionManager { + private static final Logger log = LoggingUtils.getLogger(JMXConnectionManager.class); + + private Map connections; + private MXBeanConnectionPool mxBeanPool; + + JMXConnectionManager(Map connections, MXBeanConnectionPool mxBeanPool) { + this.connections = connections; + this.mxBeanPool = mxBeanPool; + } + + JMXConnectionManager(MXBeanConnectionPool mxBeanPool) { + this(new HashMap(), mxBeanPool); + } + + public JCMDBinding getBindings(Pid pid) throws Exception { + + if (connections.containsKey(pid)) { + return connections.get(pid); + } + + try { + MXBeanConnection connection = mxBeanPool.acquire(pid.get()); + + JCMDBinding binding = new JCMDBinding(connection); + + if (binding.canCollectDiagnosticData()) { + connections.put(pid, binding); + + } else { + log.warning("vm does not run with -XX:+UnlockDiagnosticVMOptions"); + mxBeanPool.release(pid.get(), connection); + throw new UnsupportedOperationException("vm does not run with +UnlockDiagnosticVMOptions"); + } + + return binding; + + } catch (NumberFormatException nfe) { + log.warning("vm-pid cannot be parsed: " + pid); + throw nfe; + } + } + + public void release(Pid pid) { + + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/JMXReceiver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/JMXReceiver.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal; + +import com.redhat.thermostat.commands.agent.receiver.RequestReceiver; +import com.redhat.thermostat.commands.model.AgentRequest; +import com.redhat.thermostat.commands.model.WebSocketResponse; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.agent.jcmd.backend.internal.model.GCStatsModel; +import com.redhat.thermostat.agent.jcmd.backend.internal.model.JCMDBinding; +import com.redhat.thermostat.jvm.overview.agent.model.VmMapperService; +import com.redhat.thermostat.lang.schema.JSONService; +import com.redhat.thermostat.lang.schema.models.Pid; +import com.redhat.thermostat.lang.schema.models.Timestamp; + +import java.util.logging.Level; +import java.util.logging.Logger; + +class JMXReceiver implements RequestReceiver { + + private static final Logger log = LoggingUtils.getLogger(JMXReceiver.class); + + private JMXConnectionManager connectionManager; + private JSONService json; + private NetworkHandler networkHandler; + private VmMapperService mapperService; + + public JMXReceiver(JMXConnectionManager connectionManager, JSONService json, + VmMapperService mapperService, NetworkHandler networkHandler) + { + this.connectionManager = connectionManager; + this.json = json; + this.networkHandler = networkHandler; + this.mapperService = mapperService; + } + + @Override + public WebSocketResponse receive(AgentRequest request) { + + WebSocketResponse.ResponseType responseType = WebSocketResponse.ResponseType.ERROR; + String vmId = request.getJvmId(); + Pid pid = mapperService.getPid(vmId); + if (pid == null) { + return new WebSocketResponse(request.getSequenceId(), responseType); + } + + try { + JCMDBinding binding = connectionManager.getBindings(pid); + + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + String gcStats = binding.getGCStats(); + + // enable for debugging, this prints a lot of output +// log.log(Level.WARNING, "gcStats follow ----------"); +// log.log(Level.WARNING, gcStats); +// log.log(Level.WARNING, "gcStats follow end ------"); + + GCStatsModel model = new GCStatsModel(timestamp, gcStats); + String serialisedModel = json.serialiase(model); + + responseType = networkHandler.send(serialisedModel, request.getSystemId(), vmId); + + } catch (Exception ex) { + log.log(Level.WARNING, "Error!" , ex); + responseType = WebSocketResponse.ResponseType.ERROR; + } + + return new WebSocketResponse(request.getSequenceId(), responseType); + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/NetworkHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/NetworkHandler.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal; + +import com.redhat.thermostat.agent.http.HttpRequestService; +import com.redhat.thermostat.commands.model.WebSocketResponse; +import com.redhat.thermostat.common.config.experimental.ConfigurationInfoSource; +import com.redhat.thermostat.common.plugin.PluginConfiguration; + +import java.io.IOException; +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class NetworkHandler { + private static final String PLUGIN_ID = "jcmd"; + private static final String SYSTEM_PATH = "systems/"; + private static final String VM_PATH = "/jvms/"; + + private HttpRequestService httpRequestService; + + private PluginConfiguration configuration; + + public NetworkHandler(HttpRequestService httpRequestService, ConfigurationInfoSource configInfoSource) + { + this.httpRequestService = httpRequestService; + this.configuration = new ConfigurationCreator().create(configInfoSource); + } + + private URI getURI(String systemId, String vmId) throws IOException { + StringBuilder builder = new StringBuilder(); + builder.append(SYSTEM_PATH); + builder.append(systemId); + builder.append(VM_PATH); + builder.append(vmId); + return configuration.getGatewayURL().resolve(builder.toString()); + } + + public WebSocketResponse.ResponseType send(String serialisedModel, String systemId, String vmId) throws Exception { + //Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "jvmid: " + vmId + ", body: " + serialisedModel); + httpRequestService.sendHttpRequest(serialisedModel, getURI(systemId, vmId), HttpRequestService.Method.POST); + return WebSocketResponse.ResponseType.OK; + } + + static class ConfigurationCreator { + + PluginConfiguration create(ConfigurationInfoSource source) { + return new PluginConfiguration(source, PLUGIN_ID); + } + + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/model/GCStatsModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/model/GCStatsModel.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal.model; + +import com.redhat.thermostat.lang.schema.annotations.Schema; +import com.redhat.thermostat.lang.schema.annotations.Type; +import com.redhat.thermostat.lang.schema.models.Timestamp; + +@Type(description = "Full JCMD GC.class_stats data dump") +public class GCStatsModel { + @Schema(description = "The timestamp the request was made", required = true) + private Timestamp timestamp; + + @Schema(description = "The data dump", required = true) + private String payload; + + public GCStatsModel(Timestamp timestamp, String payload) { + this.timestamp = timestamp; + this.payload = payload; + } + + public String getPayload() { + return payload; + } + + public Timestamp getTimestamp() { + return timestamp; + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/model/JCMDBinding.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/main/java/com/redhat/thermostat/agent/jcmd/backend/internal/model/JCMDBinding.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal.model; + +import com.redhat.thermostat.agent.utils.management.MXBeanConnection; + +import javax.management.ObjectName; + +public class JCMDBinding { + + private MXBeanConnection connection; + + public JCMDBinding(MXBeanConnection connection) { + this.connection = connection; + } + + public boolean canCollectDiagnosticData()throws Exception { + String flags = getVmFlags(); + return flags.contains("+UnlockDiagnosticVMOptions"); + } + + public String getVmFlags() throws Exception { + return invoke("vmFlags"); + } + + public String getGCStats() throws Exception { + return invoke("gcClassStats", + new String[][] { + { + "InstBytes,InstCount,KlassBytes,CpAll," + + "annotations,MethodCount,MethodAll,ROAll," + + "RWAll,ClassName,Bytecodes,ClassLoader,Total" + } + + }); + } + + String invoke(String operation, String [][] params) throws Exception { + + return (String) connection.get().invoke(new ObjectName("com.sun.management:type=DiagnosticCommand"), + operation, params, + new String[] { String[].class.getName() }); + } + + String invoke(String operation) throws Exception { + return invoke(operation, new String[][] { null }); + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/test/java/com/redhat/thermostat/agent/jcmd/backend/internal/JCMDBackendTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/test/java/com/redhat/thermostat/agent/jcmd/backend/internal/JCMDBackendTest.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal; + +import com.redhat.thermostat.commands.agent.receiver.RequestReceiver; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.osgi.framework.BundleContext; + +import java.util.Dictionary; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class JCMDBackendTest { + + @Test + public void registerToCommandChannelOnlyOnBackendActivation() { + BundleContext context = mock(BundleContext.class); + + JCMDBackend backend = new JCMDBackend(); + // needed to pass the bundle context + backend._activate_(context); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Dictionary.class); + when(context.registerService(eq(RequestReceiver.class), + (RequestReceiver) anyObject(), + captor.capture())).thenReturn(null); + + backend.activate(); + + Dictionary dictionary = captor.getValue(); + verify(context).registerService(eq(RequestReceiver.class), + (RequestReceiver) anyObject(), + eq(dictionary)); + assertEquals("jcmd", dictionary.get("servicename")); + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/test/java/com/redhat/thermostat/agent/jcmd/backend/internal/JMXReceiverTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/test/java/com/redhat/thermostat/agent/jcmd/backend/internal/JMXReceiverTest.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal; + +import com.redhat.thermostat.agent.jcmd.backend.internal.model.GCStatsModel; +import com.redhat.thermostat.agent.jcmd.backend.internal.model.JCMDBinding; +import com.redhat.thermostat.commands.model.AgentRequest; +import com.redhat.thermostat.commands.model.WebSocketResponse; +import com.redhat.thermostat.jvm.overview.agent.model.VmMapperService; +import com.redhat.thermostat.lang.schema.JSONService; +import com.redhat.thermostat.lang.schema.models.Pid; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class JMXReceiverTest { + + private JMXConnectionManager connectionManager; + private JSONService json; + private NetworkHandler networkHandler; + private VmMapperService mapperService; + private AgentRequest request; + private JCMDBinding binding; + + private Pid pid; + + @Before + public void setup() throws Exception { + connectionManager = mock(JMXConnectionManager.class); + json = mock(JSONService.class); + networkHandler = mock(NetworkHandler.class); + mapperService = mock(VmMapperService.class); + request = mock(AgentRequest.class); + + when(request.getJvmId()).thenReturn("42"); + when(request.getSystemId()).thenReturn("0x4A"); + + pid = new Pid(42); + when(mapperService.getPid("42")).thenReturn(pid); + + binding = mock(JCMDBinding.class); + when(connectionManager.getBindings(pid)).thenReturn(binding); + } + + @Test + public void testReceiverEndQueryJCMDBinding() throws Exception { + + when(binding.getGCStats()).thenReturn("abcdefghilmnopqrstuvz"); + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + when(networkHandler.send(captor.capture(), eq("0x4A"), eq("42"))). + thenReturn(WebSocketResponse.ResponseType.OK); + + ArgumentCaptor captor2 = ArgumentCaptor.forClass(GCStatsModel.class); + when(json.serialiase(captor2.capture())).thenReturn("something.json"); + + JMXReceiver receiver = new JMXReceiver(connectionManager, json, + mapperService, networkHandler); + receiver.receive(request); + verify(binding).getGCStats(); + + Assert.assertEquals("something.json", captor.getValue()); + Assert.assertEquals("abcdefghilmnopqrstuvz", captor2.getValue().getPayload()); + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/agent/src/test/java/com/redhat/thermostat/agent/jcmd/backend/internal/model/JCMDBindingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/agent/src/test/java/com/redhat/thermostat/agent/jcmd/backend/internal/model/JCMDBindingTest.java Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.jcmd.backend.internal.model; + +import com.redhat.thermostat.agent.utils.management.MXBeanConnection; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class JCMDBindingTest { + + private MXBeanConnection connection; + private MBeanServerConnection serverConnection; + + @Before + public void setup() { + connection = mock(MXBeanConnection.class); + serverConnection = mock(MBeanServerConnection.class); + when(connection.get()).thenReturn(serverConnection); + + } + + @Test + public void testJCMDParsesJVMFlags() throws Exception { + + when(serverConnection.invoke(eq(new ObjectName("com.sun.management:type=DiagnosticCommand")), + eq("vmFlags"), any(String[][].class), + any(String[].class))). + thenReturn("+UnlockDiagnosticVMOptions -something"); + + JCMDBinding binding = new JCMDBinding(connection); + + assertTrue(binding.canCollectDiagnosticData()); + } + + @Test + public void testJCMDRetrievesAllGCClassStats() throws Exception { + + ArgumentCaptor captor = ArgumentCaptor.forClass(String[][].class); + + when(serverConnection.invoke(eq(new ObjectName("com.sun.management:type=DiagnosticCommand")), + eq("gcClassStats"), captor.capture(), + any(String[].class))).thenReturn("42"); + + JCMDBinding binding = new JCMDBinding(connection); + assertEquals("42", binding.getGCStats()); + + String parameters = captor.getValue()[0][0]; + assertEquals("InstBytes,InstCount,KlassBytes,CpAll,annotations," + + "MethodCount,MethodAll,ROAll,RWAll,ClassName,Bytecodes," + + "ClassLoader,Total", parameters); + } +} diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/distribution/assemblies/plugin-assembly.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/distribution/assemblies/plugin-assembly.xml Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,74 @@ + + + + plugin-assembly + + zip + + false + + + + + com.redhat.thermostat.agent:thermostat-jcmd-stats-collector-agent + + false + true + plugins/${thermostat.plugin} + + + + + + + thermostat-plugin.xml + + plugins/${thermostat.plugin} + true + + + configFiles + etc/plugins.d/${thermostat.plugin} + true + + + + diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/distribution/configFiles/gateway.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/distribution/configFiles/gateway.properties Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,2 @@ +# URL to the microservice provided by the Thermostat web gateway +gatewayURL=https://localhost:30000/jcmd/0.0.1 diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/distribution/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/distribution/pom.xml Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,89 @@ + + + + 4.0.0 + + + com.redhat.thermostat.agent + thermostat-jcmd-stats-collector + 2.99.0-SNAPSHOT + + + thermostat-jcmd-stats-collector-distribution + pom + + Thermostat JCMD Stats Collector Plugin distribution + + + jcmd + + + + + + maven-assembly-plugin + + + assemblies/plugin-assembly.xml + + false + + + + assemble-plugin + package + + single + + + + + + + + + + com.redhat.thermostat.agent + thermostat-jcmd-stats-collector-agent + ${project.version} + + + + + diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/distribution/thermostat-plugin.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/distribution/thermostat-plugin.xml Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,51 @@ + + + + + + agent + + com.redhat.thermostat.agent.jcmd${project.version} + + + + + diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jcmd-stats-collector/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jcmd-stats-collector/pom.xml Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,59 @@ + + + + 4.0.0 + + + com.redhat.thermostat.agent + thermostat-plugins + 2.99.0-SNAPSHOT + + + thermostat-jcmd-stats-collector + pom + + Thermostat JCMD Stats Collector plugin + + + agent + distribution + + + + diff -r bde0a709ca30 -r 1a0d260468d1 plugins/jvm-overview/pom.xml.orig --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/pom.xml.orig Mon Oct 09 15:56:10 2017 +0200 @@ -0,0 +1,59 @@ + + + + 4.0.0 + + + com.redhat.thermostat + thermostat-plugins + 1.99.12-SNAPSHOT + + + thermostat-host-overview + pom + + Thermostat Host Overview plugin + + + agent + distribution + + + + diff -r bde0a709ca30 -r 1a0d260468d1 plugins/pom.xml --- a/plugins/pom.xml Fri Oct 06 14:14:13 2017 -0400 +++ b/plugins/pom.xml Mon Oct 09 15:56:10 2017 +0200 @@ -64,6 +64,7 @@ commands vm-byteman vm-compiler + jcmd-stats-collector